aboutsummaryrefslogtreecommitdiff
path: root/crates/hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir/src')
-rw-r--r--crates/hir/src/semantics.rs92
-rw-r--r--crates/hir/src/semantics/source_to_def.rs15
2 files changed, 87 insertions, 20 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index c7f2c02e4..2d08a7704 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -117,6 +117,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
117 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { 117 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
118 self.imp.expand(macro_call) 118 self.imp.expand(macro_call)
119 } 119 }
120
121 /// If `item` has an attribute macro attached to it, expands it.
122 pub fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
123 self.imp.expand_attr_macro(item)
124 }
125
126 pub fn is_attr_macro_call(&self, item: &ast::Item) -> bool {
127 self.imp.is_attr_macro_call(item)
128 }
129
120 pub fn speculative_expand( 130 pub fn speculative_expand(
121 &self, 131 &self,
122 actual_macro_call: &ast::MacroCall, 132 actual_macro_call: &ast::MacroCall,
@@ -332,6 +342,22 @@ impl<'db> SemanticsImpl<'db> {
332 Some(node) 342 Some(node)
333 } 343 }
334 344
345 fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
346 let sa = self.analyze(item.syntax());
347 let src = InFile::new(sa.file_id, item.clone());
348 let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?;
349 let file_id = macro_call_id.as_file();
350 let node = self.db.parse_or_expand(file_id)?;
351 self.cache(node.clone(), file_id);
352 Some(node)
353 }
354
355 fn is_attr_macro_call(&self, item: &ast::Item) -> bool {
356 let sa = self.analyze(item.syntax());
357 let src = InFile::new(sa.file_id, item.clone());
358 self.with_ctx(|ctx| ctx.item_to_macro_call(src).is_some())
359 }
360
335 fn speculative_expand( 361 fn speculative_expand(
336 &self, 362 &self,
337 actual_macro_call: &ast::MacroCall, 363 actual_macro_call: &ast::MacroCall,
@@ -362,25 +388,57 @@ impl<'db> SemanticsImpl<'db> {
362 388
363 let token = successors(Some(InFile::new(sa.file_id, token)), |token| { 389 let token = successors(Some(InFile::new(sa.file_id, token)), |token| {
364 self.db.unwind_if_cancelled(); 390 self.db.unwind_if_cancelled();
365 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; 391
366 let tt = macro_call.token_tree()?; 392 for node in token.value.ancestors() {
367 if !tt.syntax().text_range().contains_range(token.value.text_range()) { 393 match_ast! {
368 return None; 394 match node {
369 } 395 ast::MacroCall(macro_call) => {
370 let file_id = sa.expand(self.db, token.with_value(&macro_call))?; 396 let tt = macro_call.token_tree()?;
371 let token = self 397 if !tt.syntax().text_range().contains_range(token.value.text_range()) {
372 .expansion_info_cache 398 return None;
373 .borrow_mut() 399 }
374 .entry(file_id) 400 let file_id = sa.expand(self.db, token.with_value(&macro_call))?;
375 .or_insert_with(|| file_id.expansion_info(self.db.upcast())) 401 let token = self
376 .as_ref()? 402 .expansion_info_cache
377 .map_token_down(token.as_ref())?; 403 .borrow_mut()
378 404 .entry(file_id)
379 if let Some(parent) = token.value.parent() { 405 .or_insert_with(|| file_id.expansion_info(self.db.upcast()))
380 self.cache(find_root(&parent), token.file_id); 406 .as_ref()?
407 .map_token_down(token.as_ref())?;
408
409 if let Some(parent) = token.value.parent() {
410 self.cache(find_root(&parent), token.file_id);
411 }
412
413 return Some(token);
414 },
415 ast::Item(item) => {
416 match self.with_ctx(|ctx| ctx.item_to_macro_call(token.with_value(item))) {
417 Some(call_id) => {
418 let file_id = call_id.as_file();
419 let token = self
420 .expansion_info_cache
421 .borrow_mut()
422 .entry(file_id)
423 .or_insert_with(|| file_id.expansion_info(self.db.upcast()))
424 .as_ref()?
425 .map_token_down(token.as_ref())?;
426
427 if let Some(parent) = token.value.parent() {
428 self.cache(find_root(&parent), token.file_id);
429 }
430
431 return Some(token);
432 }
433 None => {}
434 }
435 },
436 _ => {}
437 }
438 }
381 } 439 }
382 440
383 Some(token) 441 None
384 }) 442 })
385 .last() 443 .last()
386 .unwrap(); 444 .unwrap();
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 9a5a2255f..22e196196 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -10,7 +10,7 @@ use hir_def::{
10 ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, 10 ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
11 UnionId, VariantId, 11 UnionId, VariantId,
12}; 12};
13use hir_expand::{name::AsName, AstId, MacroDefKind}; 13use hir_expand::{name::AsName, AstId, MacroCallId, MacroDefKind};
14use rustc_hash::FxHashMap; 14use rustc_hash::FxHashMap;
15use smallvec::SmallVec; 15use smallvec::SmallVec;
16use stdx::impl_from; 16use stdx::impl_from;
@@ -145,16 +145,25 @@ impl SourceToDefCtx<'_, '_> {
145 Some((container, label_id)) 145 Some((container, label_id))
146 } 146 }
147 147
148 pub(super) fn item_to_macro_call(&mut self, src: InFile<ast::Item>) -> Option<MacroCallId> {
149 let map = self.dyn_map(src.as_ref())?;
150 map[keys::ATTR_MACRO].get(&src).copied()
151 }
152
148 fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>( 153 fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>(
149 &mut self, 154 &mut self,
150 src: InFile<Ast>, 155 src: InFile<Ast>,
151 key: Key<Ast, ID>, 156 key: Key<Ast, ID>,
152 ) -> Option<ID> { 157 ) -> Option<ID> {
153 let container = self.find_container(src.as_ref().map(|it| it.syntax()))?; 158 self.dyn_map(src.as_ref())?[key].get(&src).copied()
159 }
160
161 fn dyn_map<Ast: AstNode + 'static>(&mut self, src: InFile<&Ast>) -> Option<&DynMap> {
162 let container = self.find_container(src.map(|it| it.syntax()))?;
154 let db = self.db; 163 let db = self.db;
155 let dyn_map = 164 let dyn_map =
156 &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db)); 165 &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db));
157 dyn_map[key].get(&src).copied() 166 Some(dyn_map)
158 } 167 }
159 168
160 pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> { 169 pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> {