aboutsummaryrefslogtreecommitdiff
path: root/crates/hir/src/semantics.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir/src/semantics.rs')
-rw-r--r--crates/hir/src/semantics.rs109
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};
17use syntax::{ 17use 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
23use crate::{ 23use 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(&macro_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(&macro_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,