aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion/completion_context.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion/completion_context.rs')
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs65
1 files changed, 38 insertions, 27 deletions
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();