aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion
diff options
context:
space:
mode:
authorSeivan Heidari <[email protected]>2019-12-23 14:35:31 +0000
committerSeivan Heidari <[email protected]>2019-12-23 14:35:31 +0000
commitb21d9337d9200e2cfdc90b386591c72c302dc03e (patch)
treef81f5c08f821115cee26fa4d3ceaae88c7807fd5 /crates/ra_ide/src/completion
parent18a0937585b836ec5ed054b9ae48e0156ab6d9ef (diff)
parentce07a2daa9e53aa86a769f8641b14c2878444fbc (diff)
Merge branch 'master' into feature/themes
Diffstat (limited to 'crates/ra_ide/src/completion')
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs35
-rw-r--r--crates/ra_ide/src/completion/complete_path.rs17
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_scope.rs37
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs32
5 files changed, 97 insertions, 26 deletions
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index b6fe48627..294964887 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -27,7 +27,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
27 complete_methods(acc, ctx, &receiver_ty); 27 complete_methods(acc, ctx, &receiver_ty);
28 28
29 // Suggest .await syntax for types that implement Future trait 29 // Suggest .await syntax for types that implement Future trait
30 if ctx.analyzer.impls_future(ctx.db, receiver_ty.into_ty()) { 30 if ctx.analyzer.impls_future(ctx.db, receiver_ty) {
31 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") 31 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
32 .detail("expr.await") 32 .detail("expr.await")
33 .insert_text("await") 33 .insert_text("await")
@@ -217,6 +217,39 @@ mod tests {
217 } 217 }
218 218
219 #[test] 219 #[test]
220 fn test_method_completion_only_fitting_impls() {
221 assert_debug_snapshot!(
222 do_ref_completion(
223 r"
224 struct A<T> {}
225 impl A<u32> {
226 fn the_method(&self) {}
227 }
228 impl A<i32> {
229 fn the_other_method(&self) {}
230 }
231 fn foo(a: A<u32>) {
232 a.<|>
233 }
234 ",
235 ),
236 @r###"
237 [
238 CompletionItem {
239 label: "the_method()",
240 source_range: [243; 243),
241 delete: [243; 243),
242 insert: "the_method()$0",
243 kind: Method,
244 lookup: "the_method",
245 detail: "fn the_method(&self)",
246 },
247 ]
248 "###
249 );
250 }
251
252 #[test]
220 fn test_trait_method_completion() { 253 fn test_trait_method_completion() {
221 assert_debug_snapshot!( 254 assert_debug_snapshot!(
222 do_ref_completion( 255 do_ref_completion(
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs
index 89e0009a1..cc1f7c830 100644
--- a/crates/ra_ide/src/completion/complete_path.rs
+++ b/crates/ra_ide/src/completion/complete_path.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{Adt, Either, HasSource, PathResolution}; 3use hir::{Adt, PathResolution, ScopeDef};
4use ra_syntax::AstNode; 4use ra_syntax::AstNode;
5use test_utils::tested_by; 5use test_utils::tested_by;
6 6
@@ -18,17 +18,15 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
18 match def { 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, def, import) in module_scope { 21 for (name, def) in module_scope {
22 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def { 22 if ctx.use_item_syntax.is_some() {
23 if ctx.use_item_syntax.is_some() { 23 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def {
24 tested_by!(dont_complete_primitive_in_use); 24 tested_by!(dont_complete_primitive_in_use);
25 continue; 25 continue;
26 } 26 }
27 } 27 if let ScopeDef::Unknown = def {
28 if Some(module) == ctx.module { 28 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
29 if let Some(import) = import { 29 if &name_ref.syntax().text() == name.to_string().as_str() {
30 if let Either::A(use_tree) = import.source(ctx.db).value {
31 if use_tree.syntax().text_range().contains_inclusive(ctx.offset) {
32 // for `use self::foo<|>`, don't suggest `foo` as a completion 30 // for `use self::foo<|>`, don't suggest `foo` as a completion
33 tested_by!(dont_complete_current_use); 31 tested_by!(dont_complete_current_use);
34 continue; 32 continue;
@@ -36,6 +34,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
36 } 34 }
37 } 35 }
38 } 36 }
37
39 acc.add_resolution(ctx, name.to_string(), &def); 38 acc.add_resolution(ctx, name.to_string(), &def);
40 } 39 }
41 } 40 }
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
index 646a30c76..5470dc291 100644
--- a/crates/ra_ide/src/completion/complete_postfix.rs
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -12,7 +12,7 @@ use crate::{
12}; 12};
13 13
14pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { 14pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
15 if ctx.db.feature_flags.get("completion.enable-postfix") == false { 15 if !ctx.db.feature_flags.get("completion.enable-postfix") {
16 return; 16 return;
17 } 17 }
18 18
diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs
index d5739b58a..458d7525e 100644
--- a/crates/ra_ide/src/completion/complete_scope.rs
+++ b/crates/ra_ide/src/completion/complete_scope.rs
@@ -873,4 +873,41 @@ mod tests {
873 "### 873 "###
874 ); 874 );
875 } 875 }
876
877 #[test]
878 fn completes_local_item() {
879 assert_debug_snapshot!(
880 do_reference_completion(
881 "
882 //- /main.rs
883 fn main() {
884 return f<|>;
885 fn frobnicate() {}
886 }
887 "
888 ),
889 @r###"
890 [
891 CompletionItem {
892 label: "frobnicate()",
893 source_range: [23; 24),
894 delete: [23; 24),
895 insert: "frobnicate()$0",
896 kind: Function,
897 lookup: "frobnicate",
898 detail: "fn frobnicate()",
899 },
900 CompletionItem {
901 label: "main()",
902 source_range: [23; 24),
903 delete: [23; 24),
904 insert: "main()$0",
905 kind: Function,
906 lookup: "main",
907 detail: "fn main()",
908 },
909 ]
910 "###
911 )
912 }
876} 913}
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index b8345c91d..48d69f7e5 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -19,6 +19,7 @@ pub(crate) struct CompletionContext<'a> {
19 pub(super) offset: TextUnit, 19 pub(super) offset: TextUnit,
20 pub(super) token: SyntaxToken, 20 pub(super) token: SyntaxToken,
21 pub(super) module: Option<hir::Module>, 21 pub(super) module: Option<hir::Module>,
22 pub(super) name_ref_syntax: Option<ast::NameRef>,
22 pub(super) function_syntax: Option<ast::FnDef>, 23 pub(super) function_syntax: Option<ast::FnDef>,
23 pub(super) use_item_syntax: Option<ast::UseItem>, 24 pub(super) use_item_syntax: Option<ast::UseItem>,
24 pub(super) record_lit_syntax: Option<ast::RecordLit>, 25 pub(super) record_lit_syntax: Option<ast::RecordLit>,
@@ -54,13 +55,13 @@ impl<'a> CompletionContext<'a> {
54 let src = hir::ModuleSource::from_position(db, position); 55 let src = hir::ModuleSource::from_position(db, position);
55 let module = hir::Module::from_definition( 56 let module = hir::Module::from_definition(
56 db, 57 db,
57 hir::Source { file_id: position.file_id.into(), value: src }, 58 hir::InFile { file_id: position.file_id.into(), value: src },
58 ); 59 );
59 let token = 60 let token =
60 original_parse.tree().syntax().token_at_offset(position.offset).left_biased()?; 61 original_parse.tree().syntax().token_at_offset(position.offset).left_biased()?;
61 let analyzer = hir::SourceAnalyzer::new( 62 let analyzer = hir::SourceAnalyzer::new(
62 db, 63 db,
63 hir::Source::new(position.file_id.into(), &token.parent()), 64 hir::InFile::new(position.file_id.into(), &token.parent()),
64 Some(position.offset), 65 Some(position.offset),
65 ); 66 );
66 let mut ctx = CompletionContext { 67 let mut ctx = CompletionContext {
@@ -69,6 +70,7 @@ impl<'a> CompletionContext<'a> {
69 token, 70 token,
70 offset: position.offset, 71 offset: position.offset,
71 module, 72 module,
73 name_ref_syntax: None,
72 function_syntax: None, 74 function_syntax: None,
73 use_item_syntax: None, 75 use_item_syntax: None,
74 record_lit_syntax: None, 76 record_lit_syntax: None,
@@ -142,6 +144,8 @@ impl<'a> CompletionContext<'a> {
142 } 144 }
143 145
144 fn classify_name_ref(&mut self, original_file: SourceFile, name_ref: ast::NameRef) { 146 fn classify_name_ref(&mut self, original_file: SourceFile, name_ref: ast::NameRef) {
147 self.name_ref_syntax =
148 find_node_at_offset(original_file.syntax(), name_ref.syntax().text_range().start());
145 let name_range = name_ref.syntax().text_range(); 149 let name_range = name_ref.syntax().text_range();
146 if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() { 150 if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() {
147 self.record_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset); 151 self.record_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset);
@@ -188,10 +192,9 @@ impl<'a> CompletionContext<'a> {
188 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); 192 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
189 self.has_type_args = segment.type_arg_list().is_some(); 193 self.has_type_args = segment.type_arg_list().is_some();
190 194
191 if let Some(mut path) = hir::Path::from_ast(path.clone()) { 195 if let Some(path) = hir::Path::from_ast(path.clone()) {
192 if !path.is_ident() { 196 if let Some(path_prefix) = path.qualifier() {
193 path.segments.pop().unwrap(); 197 self.path_prefix = Some(path_prefix);
194 self.path_prefix = Some(path);
195 return; 198 return;
196 } 199 }
197 } 200 }
@@ -240,16 +243,15 @@ impl<'a> CompletionContext<'a> {
240 .expr() 243 .expr()
241 .map(|e| e.syntax().text_range()) 244 .map(|e| e.syntax().text_range())
242 .and_then(|r| find_node_with_range(original_file.syntax(), r)); 245 .and_then(|r| find_node_with_range(original_file.syntax(), r));
243 self.dot_receiver_is_ambiguous_float_literal = if let Some(ast::Expr::Literal(l)) = 246 self.dot_receiver_is_ambiguous_float_literal =
244 &self.dot_receiver 247 if let Some(ast::Expr::Literal(l)) = &self.dot_receiver {
245 { 248 match l.kind() {
246 match l.kind() { 249 ast::LiteralKind::FloatNumber { .. } => l.token().text().ends_with('.'),
247 ast::LiteralKind::FloatNumber { suffix: _ } => l.token().text().ends_with('.'), 250 _ => false,
248 _ => false, 251 }
252 } else {
253 false
249 } 254 }
250 } else {
251 false
252 }
253 } 255 }
254 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { 256 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
255 // As above 257 // As above