Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/semantics.rs')
-rw-r--r--crates/hir/src/semantics.rs52
1 files changed, 29 insertions, 23 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index b27f1fbb5d..3eac33ce99 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -892,29 +892,8 @@ impl<'db> SemanticsImpl<'db> {
f: &mut dyn FnMut(InFile<SyntaxToken>, SyntaxContextId) -> ControlFlow<T>,
) -> Option<T> {
let _p = tracing::info_span!("descend_into_macros_impl").entered();
- let (sa, span, file_id) = token
- .parent()
- .and_then(|parent| {
- self.analyze_impl(InRealFile::new(file_id, &parent).into(), None, false)
- })
- .and_then(|sa| {
- let file_id = sa.file_id.file_id()?;
- Some((
- sa,
- self.db.real_span_map(file_id).span_for_range(token.text_range()),
- HirFileId::from(file_id),
- ))
- })?;
- let mut m_cache = self.macro_call_cache.borrow_mut();
- let def_map = sa.resolver.def_map();
-
- // A stack of tokens to process, along with the file they came from
- // These are tracked to know which macro calls we still have to look into
- // the tokens themselves aren't that interesting as the span that is being used to map
- // things down never changes.
- let mut stack: Vec<(_, SmallVec<[_; 2]>)> =
- vec![(file_id, smallvec![(token, SyntaxContextId::ROOT)])];
+ let span = self.db.real_span_map(file_id).span_for_range(token.text_range());
// Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack
let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| {
@@ -926,7 +905,6 @@ impl<'db> SemanticsImpl<'db> {
.map(SmallVec::<[_; 2]>::from_iter),
)
})?;
-
// we have found a mapping for the token if the vec is non-empty
let res = mapped_tokens.is_empty().not().then_some(());
// requeue the tokens we got from mapping our current token down
@@ -934,6 +912,33 @@ impl<'db> SemanticsImpl<'db> {
res
};
+ // A stack of tokens to process, along with the file they came from
+ // These are tracked to know which macro calls we still have to look into
+ // the tokens themselves aren't that interesting as the span that is being used to map
+ // things down never changes.
+ let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![];
+ let include = self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, file_id);
+ match include {
+ Some(include) => {
+ // include! inputs are always from real files, so they only need to be handled once upfront
+ process_expansion_for_token(&mut stack, include)?;
+ }
+ None => {
+ stack.push((file_id.into(), smallvec![(token, SyntaxContextId::ROOT)]));
+ }
+ }
+
+ let (file_id, tokens) = stack.first()?;
+ // make sure we pick the token in the expanded include if we encountered an include,
+ // otherwise we'll get the wrong semantics
+ let sa =
+ tokens.first()?.0.parent().and_then(|parent| {
+ self.analyze_impl(InFile::new(*file_id, &parent), None, false)
+ })?;
+
+ let mut m_cache = self.macro_call_cache.borrow_mut();
+ let def_map = sa.resolver.def_map();
+
// Filters out all tokens that contain the given range (usually the macro call), any such
// token is redundant as the corresponding macro call has already been processed
let filter_duplicates = |tokens: &mut SmallVec<_>, range: TextRange| {
@@ -1011,6 +1016,7 @@ impl<'db> SemanticsImpl<'db> {
) {
call.as_macro_file()
} else {
+ // FIXME: This is wrong, the SourceAnalyzer might be invalid here
sa.expand(self.db, mcall.as_ref())?
};
m_cache.insert(mcall, it);