Skip to content

Commit 4261723

Browse files
bors[bot]Veykril
andauthored
Merge #10230
10230: fix: fix expansion order for fn-like macros and attributes in token descending r=Veykril a=Veykril Second attempt(now with a test 🎉). Fixes #10115 Co-authored-by: Lukas Wirth <[email protected]>
2 parents 249ebdd + 8f76e41 commit 4261723

File tree

3 files changed

+81
-55
lines changed

3 files changed

+81
-55
lines changed

crates/hir/src/semantics.rs

+52-55
Original file line numberDiff line numberDiff line change
@@ -498,68 +498,65 @@ impl<'db> SemanticsImpl<'db> {
498498
// otherwise push the remapped tokens back into the queue as they can potentially be remapped again.
499499
while let Some(token) = queue.pop() {
500500
self.db.unwind_if_cancelled();
501-
502501
let was_not_remapped = (|| {
503-
for node in token.value.ancestors() {
504-
if let Some(macro_call) = ast::MacroCall::cast(node.clone()) {
505-
let tt = match macro_call.token_tree() {
506-
Some(tt) => tt,
507-
None => continue,
508-
};
509-
let l_delim = match tt.left_delimiter_token() {
510-
Some(it) => it.text_range().end(),
511-
None => tt.syntax().text_range().start(),
512-
};
513-
let r_delim = match tt.right_delimiter_token() {
514-
Some(it) => it.text_range().start(),
515-
None => tt.syntax().text_range().end(),
516-
};
517-
if !TextRange::new(l_delim, r_delim)
518-
.contains_range(token.value.text_range())
519-
{
520-
continue;
521-
}
522-
let file_id = match sa.expand(self.db, token.with_value(&macro_call)) {
523-
Some(file_id) => file_id,
524-
None => continue,
525-
};
526-
let tokens = cache
527-
.entry(file_id)
528-
.or_insert_with(|| file_id.expansion_info(self.db.upcast()))
529-
.as_ref()?
530-
.map_token_down(self.db.upcast(), None, token.as_ref())?;
531-
532-
let len = queue.len();
533-
queue.extend(tokens.inspect(|token| {
534-
if let Some(parent) = token.value.parent() {
535-
self.cache(find_root(&parent), token.file_id);
536-
}
537-
}));
538-
return (queue.len() != len).then(|| ());
539-
} else if let Some(item) = ast::Item::cast(node.clone()) {
540-
if let Some(call_id) = self
541-
.with_ctx(|ctx| ctx.item_to_macro_call(token.with_value(item.clone())))
542-
{
543-
let file_id = call_id.as_file();
544-
let tokens = cache
545-
.entry(file_id)
546-
.or_insert_with(|| file_id.expansion_info(self.db.upcast()))
547-
.as_ref()?
548-
.map_token_down(self.db.upcast(), Some(item), token.as_ref())?;
549-
550-
let len = queue.len();
551-
queue.extend(tokens.inspect(|token| {
552-
if let Some(parent) = token.value.parent() {
553-
self.cache(find_root(&parent), token.file_id);
554-
}
555-
}));
556-
return (queue.len() != len).then(|| ());
502+
if let Some((call_id, item)) = token
503+
.value
504+
.ancestors()
505+
.filter_map(ast::Item::cast)
506+
.filter_map(|item| {
507+
self.with_ctx(|ctx| ctx.item_to_macro_call(token.with_value(item.clone())))
508+
.zip(Some(item))
509+
})
510+
.last()
511+
{
512+
let file_id = call_id.as_file();
513+
let tokens = cache
514+
.entry(file_id)
515+
.or_insert_with(|| file_id.expansion_info(self.db.upcast()))
516+
.as_ref()?
517+
.map_token_down(self.db.upcast(), Some(item), token.as_ref())?;
518+
519+
let len = queue.len();
520+
queue.extend(tokens.inspect(|token| {
521+
if let Some(parent) = token.value.parent() {
522+
self.cache(find_root(&parent), token.file_id);
557523
}
524+
}));
525+
return (queue.len() != len).then(|| ());
526+
}
527+
528+
if let Some(macro_call) = token.value.ancestors().find_map(ast::MacroCall::cast) {
529+
let tt = macro_call.token_tree()?;
530+
let l_delim = match tt.left_delimiter_token() {
531+
Some(it) => it.text_range().end(),
532+
None => tt.syntax().text_range().start(),
533+
};
534+
let r_delim = match tt.right_delimiter_token() {
535+
Some(it) => it.text_range().start(),
536+
None => tt.syntax().text_range().end(),
537+
};
538+
if !TextRange::new(l_delim, r_delim).contains_range(token.value.text_range()) {
539+
return None;
558540
}
541+
let file_id = sa.expand(self.db, token.with_value(&macro_call))?;
542+
let tokens = cache
543+
.entry(file_id)
544+
.or_insert_with(|| file_id.expansion_info(self.db.upcast()))
545+
.as_ref()?
546+
.map_token_down(self.db.upcast(), None, token.as_ref())?;
547+
548+
let len = queue.len();
549+
queue.extend(tokens.inspect(|token| {
550+
if let Some(parent) = token.value.parent() {
551+
self.cache(find_root(&parent), token.file_id);
552+
}
553+
}));
554+
return (queue.len() != len).then(|| ());
559555
}
560556
None
561557
})()
562558
.is_none();
559+
563560
if was_not_remapped {
564561
res.push(token.value)
565562
}

crates/ide/src/fixture.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Utilities for creating `Analysis` instances for tests.
2+
use hir::db::DefDatabase;
23
use ide_db::base_db::fixture::ChangeFixture;
34
use test_utils::{extract_annotations, RangeOrOffset};
45

@@ -8,6 +9,7 @@ use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange};
89
pub(crate) fn file(ra_fixture: &str) -> (Analysis, FileId) {
910
let mut host = AnalysisHost::default();
1011
let change_fixture = ChangeFixture::parse(ra_fixture);
12+
host.db.set_enable_proc_attr_macros(true);
1113
host.db.apply_change(change_fixture.change);
1214
(host.analysis(), change_fixture.files[0])
1315
}
@@ -16,6 +18,7 @@ pub(crate) fn file(ra_fixture: &str) -> (Analysis, FileId) {
1618
pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) {
1719
let mut host = AnalysisHost::default();
1820
let change_fixture = ChangeFixture::parse(ra_fixture);
21+
host.db.set_enable_proc_attr_macros(true);
1922
host.db.apply_change(change_fixture.change);
2023
let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
2124
let offset = range_or_offset.expect_offset();
@@ -26,6 +29,7 @@ pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) {
2629
pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) {
2730
let mut host = AnalysisHost::default();
2831
let change_fixture = ChangeFixture::parse(ra_fixture);
32+
host.db.set_enable_proc_attr_macros(true);
2933
host.db.apply_change(change_fixture.change);
3034
let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
3135
let range = range_or_offset.expect_range();
@@ -36,6 +40,7 @@ pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) {
3640
pub(crate) fn range_or_position(ra_fixture: &str) -> (Analysis, FileId, RangeOrOffset) {
3741
let mut host = AnalysisHost::default();
3842
let change_fixture = ChangeFixture::parse(ra_fixture);
43+
host.db.set_enable_proc_attr_macros(true);
3944
host.db.apply_change(change_fixture.change);
4045
let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
4146
(host.analysis(), file_id, range_or_offset)
@@ -45,6 +50,7 @@ pub(crate) fn range_or_position(ra_fixture: &str) -> (Analysis, FileId, RangeOrO
4550
pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(FileRange, String)>) {
4651
let mut host = AnalysisHost::default();
4752
let change_fixture = ChangeFixture::parse(ra_fixture);
53+
host.db.set_enable_proc_attr_macros(true);
4854
host.db.apply_change(change_fixture.change);
4955
let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
5056
let offset = range_or_offset.expect_offset();

crates/ide/src/goto_definition.rs

+23
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,29 @@ mod tests {
220220
assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {:?}", navs)
221221
}
222222

223+
#[test]
224+
fn goto_def_in_mac_call_in_attr_invoc() {
225+
check(
226+
r#"
227+
//- proc_macros: identity
228+
pub struct Struct {
229+
// ^^^^^^
230+
field: i32,
231+
}
232+
233+
macro_rules! identity {
234+
($($tt:tt)*) => {$($tt)*};
235+
}
236+
237+
#[proc_macros::identity]
238+
fn function() {
239+
identity!(Struct$0 { field: 0 });
240+
}
241+
242+
"#,
243+
)
244+
}
245+
223246
#[test]
224247
fn goto_def_for_extern_crate() {
225248
check(

0 commit comments

Comments
 (0)