aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2020-03-07 14:27:03 +0000
committerFlorian Diebold <[email protected]>2020-03-07 14:48:06 +0000
commit24e98121d81b75bafcd9c6005548776c00de8401 (patch)
tree976841b2501ab4501613a5f66b1004cd67f7e369
parentaff82cf7ac172f213cb5dcca637cb2c5332294c1 (diff)
Try to complete within macros
-rw-r--r--Cargo.lock1
-rw-r--r--crates/ra_hir/Cargo.toml2
-rw-r--r--crates/ra_hir/src/semantics.rs55
-rw-r--r--crates/ra_hir_expand/src/db.rs53
-rw-r--r--crates/ra_hir_expand/src/lib.rs9
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs98
-rw-r--r--crates/ra_ide/src/completion/complete_path.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_scope.rs70
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs87
9 files changed, 339 insertions, 38 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 80e778bcf..2e052d267 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -960,6 +960,7 @@ name = "ra_hir"
960version = "0.1.0" 960version = "0.1.0"
961dependencies = [ 961dependencies = [
962 "either", 962 "either",
963 "itertools",
963 "log", 964 "log",
964 "ra_db", 965 "ra_db",
965 "ra_hir_def", 966 "ra_hir_def",
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index 0555a0de7..266c4cff3 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -12,6 +12,8 @@ log = "0.4.8"
12rustc-hash = "1.1.0" 12rustc-hash = "1.1.0"
13either = "1.5.3" 13either = "1.5.3"
14 14
15itertools = "0.8.2"
16
15ra_syntax = { path = "../ra_syntax" } 17ra_syntax = { path = "../ra_syntax" }
16ra_db = { path = "../ra_db" } 18ra_db = { path = "../ra_db" }
17ra_prof = { path = "../ra_prof" } 19ra_prof = { path = "../ra_prof" }
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 965d185a4..56bd763c7 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -6,13 +6,14 @@ use std::{cell::RefCell, fmt, iter::successors};
6 6
7use hir_def::{ 7use hir_def::{
8 resolver::{self, HasResolver, Resolver}, 8 resolver::{self, HasResolver, Resolver},
9 TraitId, 9 AsMacroCall, TraitId,
10}; 10};
11use hir_expand::ExpansionInfo; 11use hir_expand::ExpansionInfo;
12use ra_db::{FileId, FileRange}; 12use ra_db::{FileId, FileRange};
13use ra_prof::profile; 13use ra_prof::profile;
14use ra_syntax::{ 14use ra_syntax::{
15 algo::skip_trivia_token, ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextUnit, 15 algo::{self, skip_trivia_token},
16 ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextUnit,
16}; 17};
17use rustc_hash::{FxHashMap, FxHashSet}; 18use rustc_hash::{FxHashMap, FxHashSet};
18 19
@@ -70,6 +71,37 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
70 Some(node) 71 Some(node)
71 } 72 }
72 73
74 pub fn expand_hypothetical(
75 &self,
76 actual_macro_call: &ast::MacroCall,
77 hypothetical_call: &ast::MacroCall,
78 token_to_map: SyntaxToken,
79 ) -> Option<(SyntaxNode, SyntaxToken)> {
80 let macro_call =
81 self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call);
82 let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
83 let macro_call_id = macro_call
84 .as_call_id(self.db, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?;
85 let macro_file = macro_call_id.as_file().macro_file().unwrap();
86 let (tt, tmap_1) =
87 hir_expand::syntax_node_to_token_tree(hypothetical_call.token_tree().unwrap().syntax())
88 .unwrap();
89 let range = token_to_map
90 .text_range()
91 .checked_sub(hypothetical_call.token_tree().unwrap().syntax().text_range().start())?;
92 let token_id = tmap_1.token_by_range(range)?;
93 let macro_def = hir_expand::db::expander(self.db, macro_call_id)?;
94 let (node, tmap_2) = hir_expand::db::parse_macro_with_arg(
95 self.db,
96 macro_file,
97 Some(std::sync::Arc::new((tt, tmap_1))),
98 )?;
99 let token_id = macro_def.0.map_id_down(token_id);
100 let range = tmap_2.range_by_token(token_id)?.by_kind(token_to_map.kind())?;
101 let token = algo::find_covering_element(&node.syntax_node(), range).into_token()?;
102 Some((node.syntax_node(), token))
103 }
104
73 pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { 105 pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
74 let parent = token.parent(); 106 let parent = token.parent();
75 let parent = self.find_file(parent); 107 let parent = self.find_file(parent);
@@ -104,6 +136,25 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
104 node.ancestors_with_macros(self.db).map(|it| it.value) 136 node.ancestors_with_macros(self.db).map(|it| it.value)
105 } 137 }
106 138
139 pub fn ancestors_at_offset_with_macros(
140 &self,
141 node: &SyntaxNode,
142 offset: TextUnit,
143 ) -> impl Iterator<Item = SyntaxNode> + '_ {
144 use itertools::Itertools;
145 node.token_at_offset(offset)
146 .map(|token| self.ancestors_with_macros(token.parent()))
147 .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
148 }
149
150 pub fn find_node_at_offset_with_macros<N: AstNode>(
151 &self,
152 node: &SyntaxNode,
153 offset: TextUnit,
154 ) -> Option<N> {
155 self.ancestors_at_offset_with_macros(node, offset).find_map(N::cast)
156 }
157
107 pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> { 158 pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
108 self.analyze(expr.syntax()).type_of(self.db, &expr) 159 self.analyze(expr.syntax()).type_of(self.db, &expr)
109 } 160 }
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index f3a84cacc..a7aa60fc9 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -130,15 +130,42 @@ pub(crate) fn macro_expand(
130 db: &dyn AstDatabase, 130 db: &dyn AstDatabase,
131 id: MacroCallId, 131 id: MacroCallId,
132) -> Result<Arc<tt::Subtree>, String> { 132) -> Result<Arc<tt::Subtree>, String> {
133 macro_expand_with_arg(db, id, None)
134}
135
136// TODO hack
137pub fn expander(
138 db: &dyn AstDatabase,
139 id: MacroCallId,
140) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
141 let lazy_id = match id {
142 MacroCallId::LazyMacro(id) => id,
143 MacroCallId::EagerMacro(_id) => {
144 // TODO
145 unimplemented!()
146 }
147 };
148
149 let loc = db.lookup_intern_macro(lazy_id);
150 let macro_rules = db.macro_def(loc.def)?;
151 Some(macro_rules)
152}
153
154pub(crate) fn macro_expand_with_arg(
155 db: &dyn AstDatabase,
156 id: MacroCallId,
157 arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>,
158) -> Result<Arc<tt::Subtree>, String> {
133 let lazy_id = match id { 159 let lazy_id = match id {
134 MacroCallId::LazyMacro(id) => id, 160 MacroCallId::LazyMacro(id) => id,
135 MacroCallId::EagerMacro(id) => { 161 MacroCallId::EagerMacro(id) => {
162 // TODO
136 return Ok(db.lookup_intern_eager_expansion(id).subtree); 163 return Ok(db.lookup_intern_eager_expansion(id).subtree);
137 } 164 }
138 }; 165 };
139 166
140 let loc = db.lookup_intern_macro(lazy_id); 167 let loc = db.lookup_intern_macro(lazy_id);
141 let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?; 168 let macro_arg = arg.or_else(|| db.macro_arg(id)).ok_or("Fail to args in to tt::TokenTree")?;
142 169
143 let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?; 170 let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
144 let tt = macro_rules.0.expand(db, lazy_id, &macro_arg.0).map_err(|err| format!("{:?}", err))?; 171 let tt = macro_rules.0.expand(db, lazy_id, &macro_arg.0).map_err(|err| format!("{:?}", err))?;
@@ -163,11 +190,23 @@ pub(crate) fn parse_macro(
163 db: &dyn AstDatabase, 190 db: &dyn AstDatabase,
164 macro_file: MacroFile, 191 macro_file: MacroFile,
165) -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> { 192) -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> {
193 parse_macro_with_arg(db, macro_file, None)
194}
195
196pub fn parse_macro_with_arg(
197 db: &dyn AstDatabase,
198 macro_file: MacroFile,
199 arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>,
200) -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> {
166 let _p = profile("parse_macro_query"); 201 let _p = profile("parse_macro_query");
167 202
168 let macro_call_id = macro_file.macro_call_id; 203 let macro_call_id = macro_file.macro_call_id;
169 let tt = db 204 let expansion = if let Some(arg) = arg {
170 .macro_expand(macro_call_id) 205 macro_expand_with_arg(db, macro_call_id, Some(arg))
206 } else {
207 db.macro_expand(macro_call_id)
208 };
209 let tt = expansion
171 .map_err(|err| { 210 .map_err(|err| {
172 // Note: 211 // Note:
173 // The final goal we would like to make all parse_macro success, 212 // The final goal we would like to make all parse_macro success,
@@ -185,15 +224,13 @@ pub(crate) fn parse_macro(
185 .collect::<Vec<_>>() 224 .collect::<Vec<_>>()
186 .join("\n"); 225 .join("\n");
187 226
188 log::warn!( 227 eprintln!(
189 "fail on macro_parse: (reason: {} macro_call: {:#}) parents: {}", 228 "fail on macro_parse: (reason: {} macro_call: {:#}) parents: {}",
190 err, 229 err, node.value, parents
191 node.value,
192 parents
193 ); 230 );
194 } 231 }
195 _ => { 232 _ => {
196 log::warn!("fail on macro_parse: (reason: {})", err); 233 eprintln!("fail on macro_parse: (reason: {})", err);
197 } 234 }
198 } 235 }
199 }) 236 })
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 3fce73e8a..92f3902dd 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -157,6 +157,13 @@ impl HirFileId {
157 } 157 }
158 } 158 }
159 } 159 }
160
161 pub fn macro_file(self) -> Option<MacroFile> {
162 match self.0 {
163 HirFileIdRepr::FileId(_) => None,
164 HirFileIdRepr::MacroFile(m) => Some(m),
165 }
166 }
160} 167}
161 168
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 169#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -296,7 +303,7 @@ pub struct ExpansionInfo {
296 exp_map: Arc<mbe::TokenMap>, 303 exp_map: Arc<mbe::TokenMap>,
297} 304}
298 305
299pub use mbe::Origin; 306pub use mbe::{syntax_node_to_token_tree, Origin};
300use ra_parser::FragmentKind; 307use ra_parser::FragmentKind;
301 308
302impl ExpansionInfo { 309impl ExpansionInfo {
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index 9145aa183..da2c4c1ab 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -584,4 +584,102 @@ mod tests {
584 "### 584 "###
585 ); 585 );
586 } 586 }
587
588 #[test]
589 fn works_in_simple_macro_1() {
590 assert_debug_snapshot!(
591 do_ref_completion(
592 r"
593 macro_rules! m { ($e:expr) => { $e } }
594 struct A { the_field: u32 }
595 fn foo(a: A) {
596 m!(a.x<|>)
597 }
598 ",
599 ),
600 @r###"
601 [
602 CompletionItem {
603 label: "the_field",
604 source_range: [156; 157),
605 delete: [156; 157),
606 insert: "the_field",
607 kind: Field,
608 detail: "u32",
609 },
610 ]
611 "###
612 );
613 }
614
615 #[test]
616 fn works_in_simple_macro_recursive() {
617 assert_debug_snapshot!(
618 do_ref_completion(
619 r"
620 macro_rules! m { ($e:expr) => { $e } }
621 struct A { the_field: u32 }
622 fn foo(a: A) {
623 m!(a.x<|>)
624 }
625 ",
626 ),
627 @r###"
628 [
629 CompletionItem {
630 label: "the_field",
631 source_range: [156; 157),
632 delete: [156; 157),
633 insert: "the_field",
634 kind: Field,
635 detail: "u32",
636 },
637 ]
638 "###
639 );
640 }
641
642 #[test]
643 fn works_in_simple_macro_2() {
644 // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery
645 assert_debug_snapshot!(
646 do_ref_completion(
647 r"
648 macro_rules! m { ($e:expr) => { $e } }
649 struct A { the_field: u32 }
650 fn foo(a: A) {
651 m!(a.<|>)
652 }
653 ",
654 ),
655 @r###"[]"###
656 );
657 }
658
659 #[test]
660 fn works_in_simple_macro_recursive_1() {
661 assert_debug_snapshot!(
662 do_ref_completion(
663 r"
664 macro_rules! m { ($e:expr) => { $e } }
665 struct A { the_field: u32 }
666 fn foo(a: A) {
667 m!(m!(m!(a.x<|>)))
668 }
669 ",
670 ),
671 @r###"
672 [
673 CompletionItem {
674 label: "the_field",
675 source_range: [162; 163),
676 delete: [162; 163),
677 insert: "the_field",
678 kind: Field,
679 detail: "u32",
680 },
681 ]
682 "###
683 );
684 }
587} 685}
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs
index 1a9699466..4fa47951a 100644
--- a/crates/ra_ide/src/completion/complete_path.rs
+++ b/crates/ra_ide/src/completion/complete_path.rs
@@ -1,4 +1,4 @@
1//! Completion of paths, including when writing a single name. 1//! Completion of paths, i.e. `some::prefix::<|>`.
2 2
3use hir::{Adt, PathResolution, ScopeDef}; 3use hir::{Adt, PathResolution, ScopeDef};
4use ra_syntax::AstNode; 4use ra_syntax::AstNode;
diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs
index 2b9a0e556..eb3c8cf1b 100644
--- a/crates/ra_ide/src/completion/complete_scope.rs
+++ b/crates/ra_ide/src/completion/complete_scope.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Completion of names from the current scope, e.g. locals and imported items.
2 2
3use crate::completion::{CompletionContext, Completions}; 3use crate::completion::{CompletionContext, Completions};
4 4
@@ -797,4 +797,72 @@ mod tests {
797 "### 797 "###
798 ) 798 )
799 } 799 }
800
801 #[test]
802 fn completes_in_simple_macro_1() {
803 assert_debug_snapshot!(
804 do_reference_completion(
805 r"
806 macro_rules! m { ($e:expr) => { $e } }
807 fn quux(x: i32) {
808 let y = 92;
809 m!(<|>);
810 }
811 "
812 ),
813 @"[]"
814 );
815 }
816
817 #[test]
818 fn completes_in_simple_macro_2() {
819 assert_debug_snapshot!(
820 do_reference_completion(
821 r"
822 macro_rules! m { ($e:expr) => { $e } }
823 fn quux(x: i32) {
824 let y = 92;
825 m!(x<|>);
826 }
827 "
828 ),
829 @r###"
830 [
831 CompletionItem {
832 label: "m!",
833 source_range: [145; 146),
834 delete: [145; 146),
835 insert: "m!($0)",
836 kind: Macro,
837 detail: "macro_rules! m",
838 },
839 CompletionItem {
840 label: "quux(…)",
841 source_range: [145; 146),
842 delete: [145; 146),
843 insert: "quux(${1:x})$0",
844 kind: Function,
845 lookup: "quux",
846 detail: "fn quux(x: i32)",
847 },
848 CompletionItem {
849 label: "x",
850 source_range: [145; 146),
851 delete: [145; 146),
852 insert: "x",
853 kind: Binding,
854 detail: "i32",
855 },
856 CompletionItem {
857 label: "y",
858 source_range: [145; 146),
859 delete: [145; 146),
860 insert: "y",
861 kind: Binding,
862 detail: "i32",
863 },
864 ]
865 "###
866 );
867 }
800} 868}
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index 9aa5a705d..81a033fcb 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -5,7 +5,7 @@ use ra_db::SourceDatabase;
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::{ 6use ra_syntax::{
7 algo::{find_covering_element, find_node_at_offset}, 7 algo::{find_covering_element, find_node_at_offset},
8 ast, AstNode, SourceFile, 8 ast, AstNode,
9 SyntaxKind::*, 9 SyntaxKind::*,
10 SyntaxNode, SyntaxToken, TextRange, TextUnit, 10 SyntaxNode, SyntaxToken, TextRange, TextUnit,
11}; 11};
@@ -20,6 +20,9 @@ pub(crate) struct CompletionContext<'a> {
20 pub(super) sema: Semantics<'a, RootDatabase>, 20 pub(super) sema: Semantics<'a, RootDatabase>,
21 pub(super) db: &'a RootDatabase, 21 pub(super) db: &'a RootDatabase,
22 pub(super) offset: TextUnit, 22 pub(super) offset: TextUnit,
23 /// The token before the cursor, in the original file.
24 pub(super) original_token: SyntaxToken,
25 /// The token before the cursor, in the macro-expanded file.
23 pub(super) token: SyntaxToken, 26 pub(super) token: SyntaxToken,
24 pub(super) module: Option<hir::Module>, 27 pub(super) module: Option<hir::Module>,
25 pub(super) name_ref_syntax: Option<ast::NameRef>, 28 pub(super) name_ref_syntax: Option<ast::NameRef>,
@@ -67,12 +70,18 @@ impl<'a> CompletionContext<'a> {
67 let edit = AtomTextEdit::insert(position.offset, "intellijRulezz".to_string()); 70 let edit = AtomTextEdit::insert(position.offset, "intellijRulezz".to_string());
68 parse.reparse(&edit).tree() 71 parse.reparse(&edit).tree()
69 }; 72 };
73 let fake_ident_token =
74 file_with_fake_ident.syntax().token_at_offset(position.offset).right_biased().unwrap();
70 75
76 // TODO: shouldn't this take the position into account? (in case we're inside a mod {})
71 let module = sema.to_module_def(position.file_id); 77 let module = sema.to_module_def(position.file_id);
72 let token = original_file.syntax().token_at_offset(position.offset).left_biased()?; 78 let original_token =
79 original_file.syntax().token_at_offset(position.offset).left_biased()?;
80 let token = sema.descend_into_macros(original_token.clone());
73 let mut ctx = CompletionContext { 81 let mut ctx = CompletionContext {
74 sema, 82 sema,
75 db, 83 db,
84 original_token,
76 token, 85 token,
77 offset: position.offset, 86 offset: position.offset,
78 module, 87 module,
@@ -95,15 +104,45 @@ impl<'a> CompletionContext<'a> {
95 has_type_args: false, 104 has_type_args: false,
96 dot_receiver_is_ambiguous_float_literal: false, 105 dot_receiver_is_ambiguous_float_literal: false,
97 }; 106 };
98 ctx.fill(&original_file, file_with_fake_ident, position.offset); 107
108 let mut original_file = original_file.syntax().clone();
109 let mut hypothetical_file = file_with_fake_ident.syntax().clone();
110 let mut offset = position.offset;
111 let mut fake_ident_token = fake_ident_token;
112
113 // Are we inside a macro call?
114 while let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
115 find_node_at_offset::<ast::MacroCall>(&original_file, offset),
116 find_node_at_offset::<ast::MacroCall>(&hypothetical_file, offset),
117 ) {
118 if let (Some(actual_expansion), Some(hypothetical_expansion)) = (
119 ctx.sema.expand(&actual_macro_call),
120 ctx.sema.expand_hypothetical(
121 &actual_macro_call,
122 &macro_call_with_fake_ident,
123 fake_ident_token,
124 ),
125 ) {
126 // TODO check that the expansions 'look the same' up to the inserted token?
127 original_file = actual_expansion;
128 hypothetical_file = hypothetical_expansion.0;
129 fake_ident_token = hypothetical_expansion.1;
130 offset = fake_ident_token.text_range().start();
131 } else {
132 break;
133 }
134 }
135
136 ctx.fill(&original_file, hypothetical_file, offset);
99 Some(ctx) 137 Some(ctx)
100 } 138 }
101 139
102 // The range of the identifier that is being completed. 140 // The range of the identifier that is being completed.
103 pub(crate) fn source_range(&self) -> TextRange { 141 pub(crate) fn source_range(&self) -> TextRange {
142 // check kind of macro-expanded token, but use range of original token
104 match self.token.kind() { 143 match self.token.kind() {
105 // workaroud when completion is triggered by trigger characters. 144 // workaroud when completion is triggered by trigger characters.
106 IDENT => self.token.text_range(), 145 IDENT => self.original_token.text_range(),
107 _ => TextRange::offset_len(self.offset, 0.into()), 146 _ => TextRange::offset_len(self.offset, 0.into()),
108 } 147 }
109 } 148 }
@@ -114,14 +153,12 @@ impl<'a> CompletionContext<'a> {
114 153
115 fn fill( 154 fn fill(
116 &mut self, 155 &mut self,
117 original_file: &ast::SourceFile, 156 original_file: &SyntaxNode,
118 file_with_fake_ident: ast::SourceFile, 157 file_with_fake_ident: SyntaxNode,
119 offset: TextUnit, 158 offset: TextUnit,
120 ) { 159 ) {
121 // First, let's try to complete a reference to some declaration. 160 // First, let's try to complete a reference to some declaration.
122 if let Some(name_ref) = 161 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(&file_with_fake_ident, offset) {
123 find_node_at_offset::<ast::NameRef>(file_with_fake_ident.syntax(), offset)
124 {
125 // Special case, `trait T { fn foo(i_am_a_name_ref) {} }`. 162 // Special case, `trait T { fn foo(i_am_a_name_ref) {} }`.
126 // See RFC#1685. 163 // See RFC#1685.
127 if is_node::<ast::Param>(name_ref.syntax()) { 164 if is_node::<ast::Param>(name_ref.syntax()) {
@@ -133,8 +170,7 @@ impl<'a> CompletionContext<'a> {
133 170
134 // Otherwise, see if this is a declaration. We can use heuristics to 171 // Otherwise, see if this is a declaration. We can use heuristics to
135 // suggest declaration names, see `CompletionKind::Magic`. 172 // suggest declaration names, see `CompletionKind::Magic`.
136 if let Some(name) = find_node_at_offset::<ast::Name>(file_with_fake_ident.syntax(), offset) 173 if let Some(name) = find_node_at_offset::<ast::Name>(&file_with_fake_ident, offset) {
137 {
138 if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) { 174 if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) {
139 let parent = bind_pat.syntax().parent(); 175 let parent = bind_pat.syntax().parent();
140 if parent.clone().and_then(ast::MatchArm::cast).is_some() 176 if parent.clone().and_then(ast::MatchArm::cast).is_some()
@@ -148,23 +184,24 @@ impl<'a> CompletionContext<'a> {
148 return; 184 return;
149 } 185 }
150 if name.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() { 186 if name.syntax().ancestors().find_map(ast::RecordFieldPatList::cast).is_some() {
151 self.record_lit_pat = find_node_at_offset(original_file.syntax(), self.offset); 187 self.record_lit_pat =
188 self.sema.find_node_at_offset_with_macros(&original_file, self.offset);
152 } 189 }
153 } 190 }
154 } 191 }
155 192
156 fn classify_name_ref(&mut self, original_file: &SourceFile, name_ref: ast::NameRef) { 193 fn classify_name_ref(&mut self, original_file: &SyntaxNode, name_ref: ast::NameRef) {
157 self.name_ref_syntax = 194 self.name_ref_syntax =
158 find_node_at_offset(original_file.syntax(), name_ref.syntax().text_range().start()); 195 find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
159 let name_range = name_ref.syntax().text_range(); 196 let name_range = name_ref.syntax().text_range();
160 if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() { 197 if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() {
161 self.record_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset); 198 self.record_lit_syntax =
199 self.sema.find_node_at_offset_with_macros(&original_file, self.offset);
162 } 200 }
163 201
164 self.impl_def = self 202 self.impl_def = self
165 .token 203 .sema
166 .parent() 204 .ancestors_with_macros(self.token.parent())
167 .ancestors()
168 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) 205 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
169 .find_map(ast::ImplDef::cast); 206 .find_map(ast::ImplDef::cast);
170 207
@@ -183,12 +220,12 @@ impl<'a> CompletionContext<'a> {
183 _ => (), 220 _ => (),
184 } 221 }
185 222
186 self.use_item_syntax = self.token.parent().ancestors().find_map(ast::UseItem::cast); 223 self.use_item_syntax =
224 self.sema.ancestors_with_macros(self.token.parent()).find_map(ast::UseItem::cast);
187 225
188 self.function_syntax = self 226 self.function_syntax = self
189 .token 227 .sema
190 .parent() 228 .ancestors_with_macros(self.token.parent())
191 .ancestors()
192 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) 229 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
193 .find_map(ast::FnDef::cast); 230 .find_map(ast::FnDef::cast);
194 231
@@ -242,7 +279,7 @@ impl<'a> CompletionContext<'a> {
242 279
243 if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) { 280 if let Some(off) = name_ref.syntax().text_range().start().checked_sub(2.into()) {
244 if let Some(if_expr) = 281 if let Some(if_expr) =
245 find_node_at_offset::<ast::IfExpr>(original_file.syntax(), off) 282 self.sema.find_node_at_offset_with_macros::<ast::IfExpr>(original_file, off)
246 { 283 {
247 if if_expr.syntax().text_range().end() 284 if if_expr.syntax().text_range().end()
248 < name_ref.syntax().text_range().start() 285 < name_ref.syntax().text_range().start()
@@ -259,7 +296,7 @@ impl<'a> CompletionContext<'a> {
259 self.dot_receiver = field_expr 296 self.dot_receiver = field_expr
260 .expr() 297 .expr()
261 .map(|e| e.syntax().text_range()) 298 .map(|e| e.syntax().text_range())
262 .and_then(|r| find_node_with_range(original_file.syntax(), r)); 299 .and_then(|r| find_node_with_range(original_file, r));
263 self.dot_receiver_is_ambiguous_float_literal = 300 self.dot_receiver_is_ambiguous_float_literal =
264 if let Some(ast::Expr::Literal(l)) = &self.dot_receiver { 301 if let Some(ast::Expr::Literal(l)) = &self.dot_receiver {
265 match l.kind() { 302 match l.kind() {
@@ -275,7 +312,7 @@ impl<'a> CompletionContext<'a> {
275 self.dot_receiver = method_call_expr 312 self.dot_receiver = method_call_expr
276 .expr() 313 .expr()
277 .map(|e| e.syntax().text_range()) 314 .map(|e| e.syntax().text_range())
278 .and_then(|r| find_node_with_range(original_file.syntax(), r)); 315 .and_then(|r| find_node_with_range(original_file, r));
279 self.is_call = true; 316 self.is_call = true;
280 } 317 }
281 } 318 }