aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-02-26 12:04:22 +0000
committerGitHub <[email protected]>2020-02-26 12:04:22 +0000
commit5c64ad27e041bcdb281c0a751720ceb3a6369d04 (patch)
tree12d89798f61b276f8bd640db07276a7d4e92b1c2 /crates/ra_ide/src/completion
parent04deae3dba7c9b7054f7a1d64e4b93a05aecc132 (diff)
parentc3a4c4429de83450654795534e64e878a774a088 (diff)
Merge pull request #3222 from matklad/identity
Introduce Semantics API
Diffstat (limited to 'crates/ra_ide/src/completion')
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs4
-rw-r--r--crates/ra_ide/src/completion/complete_macro_in_item_position.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_path.rs4
-rw-r--r--crates/ra_ide/src/completion/complete_pattern.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_record_literal.rs5
-rw-r--r--crates/ra_ide/src/completion/complete_record_pattern.rs5
-rw-r--r--crates/ra_ide/src/completion/complete_scope.rs4
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs33
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs65
10 files changed, 66 insertions, 60 deletions
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index 2ca78c927..a6e0158b2 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -16,7 +16,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
16 _ => return, 16 _ => return,
17 }; 17 };
18 18
19 let receiver_ty = match ctx.analyzer.type_of(ctx.db, &dot_receiver) { 19 let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) {
20 Some(ty) => ty, 20 Some(ty) => ty,
21 _ => return, 21 _ => return,
22 }; 22 };
@@ -55,7 +55,7 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Ty
55fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { 55fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
56 if let Some(krate) = ctx.module.map(|it| it.krate()) { 56 if let Some(krate) = ctx.module.map(|it| it.krate()) {
57 let mut seen_methods = FxHashSet::default(); 57 let mut seen_methods = FxHashSet::default();
58 let traits_in_scope = ctx.analyzer.traits_in_scope(ctx.db); 58 let traits_in_scope = ctx.scope().traits_in_scope();
59 receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| { 59 receiver.iterate_method_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, func| {
60 if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) { 60 if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) {
61 acc.add_function(ctx, func); 61 acc.add_function(ctx, func);
diff --git a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
index faadd1e3f..1866d9e6c 100644
--- a/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
+++ b/crates/ra_ide/src/completion/complete_macro_in_item_position.rs
@@ -5,7 +5,7 @@ use crate::completion::{CompletionContext, Completions};
5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) { 5pub(super) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) {
6 // Show only macros in top level. 6 // Show only macros in top level.
7 if ctx.is_new_item { 7 if ctx.is_new_item {
8 ctx.analyzer.process_all_names(ctx.db, &mut |name, res| { 8 ctx.scope().process_all_names(&mut |name, res| {
9 if let hir::ScopeDef::MacroDef(mac) = res { 9 if let hir::ScopeDef::MacroDef(mac) = res {
10 acc.add_macro(ctx, Some(name.to_string()), mac); 10 acc.add_macro(ctx, Some(name.to_string()), mac);
11 } 11 }
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs
index 2d7f09a6c..c626e90cc 100644
--- a/crates/ra_ide/src/completion/complete_path.rs
+++ b/crates/ra_ide/src/completion/complete_path.rs
@@ -11,7 +11,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
11 Some(path) => path.clone(), 11 Some(path) => path.clone(),
12 _ => return, 12 _ => return,
13 }; 13 };
14 let def = match ctx.analyzer.resolve_hir_path(ctx.db, &path) { 14 let def = match ctx.scope().resolve_hir_path(&path) {
15 Some(PathResolution::Def(def)) => def, 15 Some(PathResolution::Def(def)) => def,
16 _ => return, 16 _ => return,
17 }; 17 };
@@ -49,7 +49,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
49 // FIXME: complete T::AssocType 49 // FIXME: complete T::AssocType
50 let krate = ctx.module.map(|m| m.krate()); 50 let krate = ctx.module.map(|m| m.krate());
51 if let Some(krate) = krate { 51 if let Some(krate) = krate {
52 let traits_in_scope = ctx.analyzer.traits_in_scope(ctx.db); 52 let traits_in_scope = ctx.scope().traits_in_scope();
53 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { 53 ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| {
54 match item { 54 match item {
55 hir::AssocItem::Function(func) => { 55 hir::AssocItem::Function(func) => {
diff --git a/crates/ra_ide/src/completion/complete_pattern.rs b/crates/ra_ide/src/completion/complete_pattern.rs
index fd03b1c40..c2c6ca002 100644
--- a/crates/ra_ide/src/completion/complete_pattern.rs
+++ b/crates/ra_ide/src/completion/complete_pattern.rs
@@ -9,7 +9,7 @@ pub(super) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
9 } 9 }
10 // FIXME: ideally, we should look at the type we are matching against and 10 // FIXME: ideally, we should look at the type we are matching against and
11 // suggest variants + auto-imports 11 // suggest variants + auto-imports
12 ctx.analyzer.process_all_names(ctx.db, &mut |name, res| { 12 ctx.scope().process_all_names(&mut |name, res| {
13 let def = match &res { 13 let def = match &res {
14 hir::ScopeDef::ModuleDef(def) => def, 14 hir::ScopeDef::ModuleDef(def) => def,
15 _ => return, 15 _ => return,
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
index 5470dc291..8a74f993a 100644
--- a/crates/ra_ide/src/completion/complete_postfix.rs
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -29,7 +29,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
29 dot_receiver.syntax().text().to_string() 29 dot_receiver.syntax().text().to_string()
30 }; 30 };
31 31
32 let receiver_ty = match ctx.analyzer.type_of(ctx.db, &dot_receiver) { 32 let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) {
33 Some(it) => it, 33 Some(it) => it,
34 None => return, 34 None => return,
35 }; 35 };
diff --git a/crates/ra_ide/src/completion/complete_record_literal.rs b/crates/ra_ide/src/completion/complete_record_literal.rs
index 577c394d2..f98353d76 100644
--- a/crates/ra_ide/src/completion/complete_record_literal.rs
+++ b/crates/ra_ide/src/completion/complete_record_literal.rs
@@ -5,10 +5,7 @@ use crate::completion::{CompletionContext, Completions};
5/// Complete fields in fields literals. 5/// Complete fields in fields literals.
6pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionContext) { 6pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionContext) {
7 let (ty, variant) = match ctx.record_lit_syntax.as_ref().and_then(|it| { 7 let (ty, variant) = match ctx.record_lit_syntax.as_ref().and_then(|it| {
8 Some(( 8 Some((ctx.sema.type_of_expr(&it.clone().into())?, ctx.sema.resolve_record_literal(it)?))
9 ctx.analyzer.type_of(ctx.db, &it.clone().into())?,
10 ctx.analyzer.resolve_record_literal(it)?,
11 ))
12 }) { 9 }) {
13 Some(it) => it, 10 Some(it) => it,
14 _ => return, 11 _ => return,
diff --git a/crates/ra_ide/src/completion/complete_record_pattern.rs b/crates/ra_ide/src/completion/complete_record_pattern.rs
index a56c7e3a1..9bdeae49f 100644
--- a/crates/ra_ide/src/completion/complete_record_pattern.rs
+++ b/crates/ra_ide/src/completion/complete_record_pattern.rs
@@ -4,10 +4,7 @@ use crate::completion::{CompletionContext, Completions};
4 4
5pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionContext) { 5pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionContext) {
6 let (ty, variant) = match ctx.record_lit_pat.as_ref().and_then(|it| { 6 let (ty, variant) = match ctx.record_lit_pat.as_ref().and_then(|it| {
7 Some(( 7 Some((ctx.sema.type_of_pat(&it.clone().into())?, ctx.sema.resolve_record_pattern(it)?))
8 ctx.analyzer.type_of_pat(ctx.db, &it.clone().into())?,
9 ctx.analyzer.resolve_record_pattern(it)?,
10 ))
11 }) { 8 }) {
12 Some(it) => it, 9 Some(it) => it,
13 _ => return, 10 _ => return,
diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs
index e2ee86dd1..aad016d4a 100644
--- a/crates/ra_ide/src/completion/complete_scope.rs
+++ b/crates/ra_ide/src/completion/complete_scope.rs
@@ -7,9 +7,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
7 return; 7 return;
8 } 8 }
9 9
10 ctx.analyzer.process_all_names(ctx.db, &mut |name, res| { 10 ctx.scope().process_all_names(&mut |name, res| acc.add_resolution(ctx, name.to_string(), &res));
11 acc.add_resolution(ctx, name.to_string(), &res)
12 });
13} 11}
14 12
15#[cfg(test)] 13#[cfg(test)]
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs
index 83628e35c..9a27c164b 100644
--- a/crates/ra_ide/src/completion/complete_trait_impl.rs
+++ b/crates/ra_ide/src/completion/complete_trait_impl.rs
@@ -64,11 +64,12 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
64 if let (Some(trigger), Some(impl_block)) = (trigger, impl_block) { 64 if let (Some(trigger), Some(impl_block)) = (trigger, impl_block) {
65 match trigger.kind() { 65 match trigger.kind() {
66 SyntaxKind::FN_DEF => { 66 SyntaxKind::FN_DEF => {
67 for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block) 67 for missing_fn in
68 .iter() 68 get_missing_impl_items(&ctx.sema, &impl_block).iter().filter_map(|item| {
69 .filter_map(|item| match item { 69 match item {
70 hir::AssocItem::Function(fn_item) => Some(fn_item), 70 hir::AssocItem::Function(fn_item) => Some(fn_item),
71 _ => None, 71 _ => None,
72 }
72 }) 73 })
73 { 74 {
74 add_function_impl(&trigger, acc, ctx, &missing_fn); 75 add_function_impl(&trigger, acc, ctx, &missing_fn);
@@ -76,11 +77,12 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
76 } 77 }
77 78
78 SyntaxKind::TYPE_ALIAS_DEF => { 79 SyntaxKind::TYPE_ALIAS_DEF => {
79 for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block) 80 for missing_fn in
80 .iter() 81 get_missing_impl_items(&ctx.sema, &impl_block).iter().filter_map(|item| {
81 .filter_map(|item| match item { 82 match item {
82 hir::AssocItem::TypeAlias(type_item) => Some(type_item), 83 hir::AssocItem::TypeAlias(type_item) => Some(type_item),
83 _ => None, 84 _ => None,
85 }
84 }) 86 })
85 { 87 {
86 add_type_alias_impl(&trigger, acc, ctx, &missing_fn); 88 add_type_alias_impl(&trigger, acc, ctx, &missing_fn);
@@ -88,11 +90,12 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
88 } 90 }
89 91
90 SyntaxKind::CONST_DEF => { 92 SyntaxKind::CONST_DEF => {
91 for missing_fn in get_missing_impl_items(ctx.db, &ctx.analyzer, &impl_block) 93 for missing_fn in
92 .iter() 94 get_missing_impl_items(&ctx.sema, &impl_block).iter().filter_map(|item| {
93 .filter_map(|item| match item { 95 match item {
94 hir::AssocItem::Const(const_item) => Some(const_item), 96 hir::AssocItem::Const(const_item) => Some(const_item),
95 _ => None, 97 _ => None,
98 }
96 }) 99 })
97 { 100 {
98 add_const_impl(&trigger, acc, ctx, &missing_fn); 101 add_const_impl(&trigger, acc, ctx, &missing_fn);
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index 8678a3234..81321a897 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -1,9 +1,11 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{Semantics, SemanticsScope};
4use ra_db::SourceDatabase;
3use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
4use ra_syntax::{ 6use ra_syntax::{
5 algo::{find_covering_element, find_node_at_offset}, 7 algo::{find_covering_element, find_node_at_offset},
6 ast, AstNode, Parse, SourceFile, 8 ast, AstNode, SourceFile,
7 SyntaxKind::*, 9 SyntaxKind::*,
8 SyntaxNode, SyntaxToken, TextRange, TextUnit, 10 SyntaxNode, SyntaxToken, TextRange, TextUnit,
9}; 11};
@@ -15,8 +17,8 @@ use crate::FilePosition;
15/// exactly is the cursor, syntax-wise. 17/// exactly is the cursor, syntax-wise.
16#[derive(Debug)] 18#[derive(Debug)]
17pub(crate) struct CompletionContext<'a> { 19pub(crate) struct CompletionContext<'a> {
20 pub(super) sema: Semantics<'a, RootDatabase>,
18 pub(super) db: &'a RootDatabase, 21 pub(super) db: &'a RootDatabase,
19 pub(super) analyzer: hir::SourceAnalyzer,
20 pub(super) offset: TextUnit, 22 pub(super) offset: TextUnit,
21 pub(super) token: SyntaxToken, 23 pub(super) token: SyntaxToken,
22 pub(super) module: Option<hir::Module>, 24 pub(super) module: Option<hir::Module>,
@@ -51,20 +53,26 @@ pub(crate) struct CompletionContext<'a> {
51impl<'a> CompletionContext<'a> { 53impl<'a> CompletionContext<'a> {
52 pub(super) fn new( 54 pub(super) fn new(
53 db: &'a RootDatabase, 55 db: &'a RootDatabase,
54 original_parse: &'a Parse<ast::SourceFile>,
55 position: FilePosition, 56 position: FilePosition,
56 ) -> Option<CompletionContext<'a>> { 57 ) -> Option<CompletionContext<'a>> {
57 let mut sb = hir::SourceBinder::new(db); 58 let sema = Semantics::new(db);
58 let module = sb.to_module_def(position.file_id); 59
59 let token = 60 let original_file = sema.parse(position.file_id);
60 original_parse.tree().syntax().token_at_offset(position.offset).left_biased()?; 61
61 let analyzer = sb.analyze( 62 // Insert a fake ident to get a valid parse tree. We will use this file
62 hir::InFile::new(position.file_id.into(), &token.parent()), 63 // to determine context, though the original_file will be used for
63 Some(position.offset), 64 // actual completion.
64 ); 65 let file_with_fake_ident = {
66 let parse = db.parse(position.file_id);
67 let edit = AtomTextEdit::insert(position.offset, "intellijRulezz".to_string());
68 parse.reparse(&edit).tree()
69 };
70
71 let module = sema.to_module_def(position.file_id);
72 let token = original_file.syntax().token_at_offset(position.offset).left_biased()?;
65 let mut ctx = CompletionContext { 73 let mut ctx = CompletionContext {
74 sema,
66 db, 75 db,
67 analyzer,
68 token, 76 token,
69 offset: position.offset, 77 offset: position.offset,
70 module, 78 module,
@@ -87,7 +95,7 @@ impl<'a> CompletionContext<'a> {
87 has_type_args: false, 95 has_type_args: false,
88 dot_receiver_is_ambiguous_float_literal: false, 96 dot_receiver_is_ambiguous_float_literal: false,
89 }; 97 };
90 ctx.fill(&original_parse, position.offset); 98 ctx.fill(&original_file, file_with_fake_ident, position.offset);
91 Some(ctx) 99 Some(ctx)
92 } 100 }
93 101
@@ -100,29 +108,33 @@ impl<'a> CompletionContext<'a> {
100 } 108 }
101 } 109 }
102 110
103 fn fill(&mut self, original_parse: &'a Parse<ast::SourceFile>, offset: TextUnit) { 111 pub(crate) fn scope(&self) -> SemanticsScope<'_, RootDatabase> {
104 // Insert a fake ident to get a valid parse tree. We will use this file 112 self.sema.scope_at_offset(&self.token.parent(), self.offset)
105 // to determine context, though the original_file will be used for 113 }
106 // actual completion.
107 let file = {
108 let edit = AtomTextEdit::insert(offset, "intellijRulezz".to_string());
109 original_parse.reparse(&edit).tree()
110 };
111 114
115 fn fill(
116 &mut self,
117 original_file: &ast::SourceFile,
118 file_with_fake_ident: ast::SourceFile,
119 offset: TextUnit,
120 ) {
112 // First, let's try to complete a reference to some declaration. 121 // First, let's try to complete a reference to some declaration.
113 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), offset) { 122 if let Some(name_ref) =
123 find_node_at_offset::<ast::NameRef>(file_with_fake_ident.syntax(), offset)
124 {
114 // Special case, `trait T { fn foo(i_am_a_name_ref) {} }`. 125 // Special case, `trait T { fn foo(i_am_a_name_ref) {} }`.
115 // See RFC#1685. 126 // See RFC#1685.
116 if is_node::<ast::Param>(name_ref.syntax()) { 127 if is_node::<ast::Param>(name_ref.syntax()) {
117 self.is_param = true; 128 self.is_param = true;
118 return; 129 return;
119 } 130 }
120 self.classify_name_ref(original_parse.tree(), name_ref); 131 self.classify_name_ref(original_file, name_ref);
121 } 132 }
122 133
123 // Otherwise, see if this is a declaration. We can use heuristics to 134 // Otherwise, see if this is a declaration. We can use heuristics to
124 // suggest declaration names, see `CompletionKind::Magic`. 135 // suggest declaration names, see `CompletionKind::Magic`.
125 if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), offset) { 136 if let Some(name) = find_node_at_offset::<ast::Name>(file_with_fake_ident.syntax(), offset)
137 {
126 if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) { 138 if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) {
127 let parent = bind_pat.syntax().parent(); 139 let parent = bind_pat.syntax().parent();
128 if parent.clone().and_then(ast::MatchArm::cast).is_some() 140 if parent.clone().and_then(ast::MatchArm::cast).is_some()
@@ -136,13 +148,12 @@ impl<'a> CompletionContext<'a> {
136 return; 148 return;
137 } 149 }
138 if name.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() { 150 if name.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() {
139 self.record_lit_pat = 151 self.record_lit_pat = find_node_at_offset(original_file.syntax(), self.offset);
140 find_node_at_offset(original_parse.tree().syntax(), self.offset);
141 } 152 }
142 } 153 }
143 } 154 }
144 155
145 fn classify_name_ref(&mut self, original_file: SourceFile, name_ref: ast::NameRef) { 156 fn classify_name_ref(&mut self, original_file: &SourceFile, name_ref: ast::NameRef) {
146 self.name_ref_syntax = 157 self.name_ref_syntax =
147 find_node_at_offset(original_file.syntax(), name_ref.syntax().text_range().start()); 158 find_node_at_offset(original_file.syntax(), name_ref.syntax().text_range().start());
148 let name_range = name_ref.syntax().text_range(); 159 let name_range = name_ref.syntax().text_range();