diff options
Diffstat (limited to 'crates/hir/src/semantics.rs')
-rw-r--r-- | crates/hir/src/semantics.rs | 109 |
1 files changed, 88 insertions, 21 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index c7f2c02e4..613266e07 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -17,7 +17,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
17 | use syntax::{ | 17 | use syntax::{ |
18 | algo::find_node_at_offset, | 18 | algo::find_node_at_offset, |
19 | ast::{self, GenericParamsOwner, LoopBodyOwner}, | 19 | ast::{self, GenericParamsOwner, LoopBodyOwner}, |
20 | match_ast, AstNode, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize, | 20 | match_ast, AstNode, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize, |
21 | }; | 21 | }; |
22 | 22 | ||
23 | use crate::{ | 23 | use crate::{ |
@@ -35,8 +35,9 @@ pub enum PathResolution { | |||
35 | Def(ModuleDef), | 35 | Def(ModuleDef), |
36 | /// A local binding (only value namespace) | 36 | /// A local binding (only value namespace) |
37 | Local(Local), | 37 | Local(Local), |
38 | /// A generic parameter | 38 | /// A type parameter |
39 | TypeParam(TypeParam), | 39 | TypeParam(TypeParam), |
40 | /// A const parameter | ||
40 | ConstParam(ConstParam), | 41 | ConstParam(ConstParam), |
41 | SelfType(Impl), | 42 | SelfType(Impl), |
42 | Macro(MacroDef), | 43 | Macro(MacroDef), |
@@ -117,6 +118,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
117 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { | 118 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { |
118 | self.imp.expand(macro_call) | 119 | self.imp.expand(macro_call) |
119 | } | 120 | } |
121 | |||
122 | /// If `item` has an attribute macro attached to it, expands it. | ||
123 | pub fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> { | ||
124 | self.imp.expand_attr_macro(item) | ||
125 | } | ||
126 | |||
127 | pub fn is_attr_macro_call(&self, item: &ast::Item) -> bool { | ||
128 | self.imp.is_attr_macro_call(item) | ||
129 | } | ||
130 | |||
120 | pub fn speculative_expand( | 131 | pub fn speculative_expand( |
121 | &self, | 132 | &self, |
122 | actual_macro_call: &ast::MacroCall, | 133 | actual_macro_call: &ast::MacroCall, |
@@ -181,7 +192,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
181 | node: &SyntaxNode, | 192 | node: &SyntaxNode, |
182 | offset: TextSize, | 193 | offset: TextSize, |
183 | ) -> Option<N> { | 194 | ) -> Option<N> { |
184 | if let Some(it) = find_node_at_offset(&node, offset) { | 195 | if let Some(it) = find_node_at_offset(node, offset) { |
185 | return Some(it); | 196 | return Some(it); |
186 | } | 197 | } |
187 | 198 | ||
@@ -332,6 +343,22 @@ impl<'db> SemanticsImpl<'db> { | |||
332 | Some(node) | 343 | Some(node) |
333 | } | 344 | } |
334 | 345 | ||
346 | fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> { | ||
347 | let sa = self.analyze(item.syntax()); | ||
348 | let src = InFile::new(sa.file_id, item.clone()); | ||
349 | let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?; | ||
350 | let file_id = macro_call_id.as_file(); | ||
351 | let node = self.db.parse_or_expand(file_id)?; | ||
352 | self.cache(node.clone(), file_id); | ||
353 | Some(node) | ||
354 | } | ||
355 | |||
356 | fn is_attr_macro_call(&self, item: &ast::Item) -> bool { | ||
357 | let sa = self.analyze(item.syntax()); | ||
358 | let src = InFile::new(sa.file_id, item.clone()); | ||
359 | self.with_ctx(|ctx| ctx.item_to_macro_call(src).is_some()) | ||
360 | } | ||
361 | |||
335 | fn speculative_expand( | 362 | fn speculative_expand( |
336 | &self, | 363 | &self, |
337 | actual_macro_call: &ast::MacroCall, | 364 | actual_macro_call: &ast::MacroCall, |
@@ -362,25 +389,65 @@ impl<'db> SemanticsImpl<'db> { | |||
362 | 389 | ||
363 | let token = successors(Some(InFile::new(sa.file_id, token)), |token| { | 390 | let token = successors(Some(InFile::new(sa.file_id, token)), |token| { |
364 | self.db.unwind_if_cancelled(); | 391 | self.db.unwind_if_cancelled(); |
365 | let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; | 392 | |
366 | let tt = macro_call.token_tree()?; | 393 | for node in token.value.ancestors() { |
367 | if !tt.syntax().text_range().contains_range(token.value.text_range()) { | 394 | match_ast! { |
368 | return None; | 395 | match node { |
369 | } | 396 | ast::MacroCall(macro_call) => { |
370 | let file_id = sa.expand(self.db, token.with_value(¯o_call))?; | 397 | let tt = macro_call.token_tree()?; |
371 | let token = self | 398 | let l_delim = match tt.left_delimiter_token() { |
372 | .expansion_info_cache | 399 | Some(it) => it.text_range().end(), |
373 | .borrow_mut() | 400 | None => tt.syntax().text_range().start() |
374 | .entry(file_id) | 401 | }; |
375 | .or_insert_with(|| file_id.expansion_info(self.db.upcast())) | 402 | let r_delim = match tt.right_delimiter_token() { |
376 | .as_ref()? | 403 | Some(it) => it.text_range().start(), |
377 | .map_token_down(token.as_ref())?; | 404 | None => tt.syntax().text_range().end() |
378 | 405 | }; | |
379 | if let Some(parent) = token.value.parent() { | 406 | if !TextRange::new(l_delim, r_delim).contains_range(token.value.text_range()) { |
380 | self.cache(find_root(&parent), token.file_id); | 407 | return None; |
408 | } | ||
409 | let file_id = sa.expand(self.db, token.with_value(¯o_call))?; | ||
410 | let token = self | ||
411 | .expansion_info_cache | ||
412 | .borrow_mut() | ||
413 | .entry(file_id) | ||
414 | .or_insert_with(|| file_id.expansion_info(self.db.upcast())) | ||
415 | .as_ref()? | ||
416 | .map_token_down(token.as_ref())?; | ||
417 | |||
418 | if let Some(parent) = token.value.parent() { | ||
419 | self.cache(find_root(&parent), token.file_id); | ||
420 | } | ||
421 | |||
422 | return Some(token); | ||
423 | }, | ||
424 | ast::Item(item) => { | ||
425 | match self.with_ctx(|ctx| ctx.item_to_macro_call(token.with_value(item))) { | ||
426 | Some(call_id) => { | ||
427 | let file_id = call_id.as_file(); | ||
428 | let token = self | ||
429 | .expansion_info_cache | ||
430 | .borrow_mut() | ||
431 | .entry(file_id) | ||
432 | .or_insert_with(|| file_id.expansion_info(self.db.upcast())) | ||
433 | .as_ref()? | ||
434 | .map_token_down(token.as_ref())?; | ||
435 | |||
436 | if let Some(parent) = token.value.parent() { | ||
437 | self.cache(find_root(&parent), token.file_id); | ||
438 | } | ||
439 | |||
440 | return Some(token); | ||
441 | } | ||
442 | None => {} | ||
443 | } | ||
444 | }, | ||
445 | _ => {} | ||
446 | } | ||
447 | } | ||
381 | } | 448 | } |
382 | 449 | ||
383 | Some(token) | 450 | None |
384 | }) | 451 | }) |
385 | .last() | 452 | .last() |
386 | .unwrap(); | 453 | .unwrap(); |
@@ -677,7 +744,7 @@ impl<'db> SemanticsImpl<'db> { | |||
677 | return None; | 744 | return None; |
678 | } | 745 | } |
679 | 746 | ||
680 | let func = self.resolve_method_call(&method_call_expr).map(Function::from)?; | 747 | let func = self.resolve_method_call(method_call_expr).map(Function::from)?; |
681 | let res = match func.self_param(self.db)?.access(self.db) { | 748 | let res = match func.self_param(self.db)?.access(self.db) { |
682 | Access::Shared | Access::Exclusive => true, | 749 | Access::Shared | Access::Exclusive => true, |
683 | Access::Owned => false, | 750 | Access::Owned => false, |