Skip to content

Commit f0e39c7

Browse files
committed
Add some more hir_expand::files conversions
1 parent e65ddda commit f0e39c7

File tree

6 files changed

+137
-64
lines changed

6 files changed

+137
-64
lines changed

crates/hir-expand/src/files.rs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,49 @@ impl FilePosition {
4242
FilePositionWrapper { file_id: self.file_id.file_id(db), offset: self.offset }
4343
}
4444
}
45+
46+
impl From<FileRange> for HirFileRange {
47+
fn from(value: FileRange) -> Self {
48+
HirFileRange { file_id: value.file_id.into(), range: value.range }
49+
}
50+
}
51+
52+
impl From<FilePosition> for HirFilePosition {
53+
fn from(value: FilePosition) -> Self {
54+
HirFilePosition { file_id: value.file_id.into(), offset: value.offset }
55+
}
56+
}
57+
58+
impl FilePositionWrapper<span::FileId> {
59+
pub fn with_edition(self, db: &dyn ExpandDatabase, edition: span::Edition) -> FilePosition {
60+
FilePositionWrapper {
61+
file_id: EditionedFileId::new(db, self.file_id, edition),
62+
offset: self.offset,
63+
}
64+
}
65+
}
66+
67+
impl FileRangeWrapper<span::FileId> {
68+
pub fn with_edition(self, db: &dyn ExpandDatabase, edition: span::Edition) -> FileRange {
69+
FileRangeWrapper {
70+
file_id: EditionedFileId::new(db, self.file_id, edition),
71+
range: self.range,
72+
}
73+
}
74+
}
75+
76+
impl<T> InFileWrapper<span::FileId, T> {
77+
pub fn with_edition(self, db: &dyn ExpandDatabase, edition: span::Edition) -> InRealFile<T> {
78+
InRealFile { file_id: EditionedFileId::new(db, self.file_id, edition), value: self.value }
79+
}
80+
}
81+
82+
impl HirFileRange {
83+
pub fn file_range(self) -> Option<FileRange> {
84+
Some(FileRange { file_id: self.file_id.file_id()?, range: self.range })
85+
}
86+
}
87+
4588
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
4689
pub struct FileRangeWrapper<FileKind> {
4790
pub file_id: FileKind,
@@ -194,6 +237,9 @@ impl<FileId: Copy, N: AstNode> InFileWrapper<FileId, N> {
194237
pub fn syntax(&self) -> InFileWrapper<FileId, &SyntaxNode> {
195238
self.with_value(self.value.syntax())
196239
}
240+
pub fn node_file_range(&self) -> FileRangeWrapper<FileId> {
241+
FileRangeWrapper { file_id: self.file_id, range: self.value.syntax().text_range() }
242+
}
197243
}
198244

199245
impl<FileId: Copy, N: AstNode> InFileWrapper<FileId, &N> {
@@ -204,9 +250,9 @@ impl<FileId: Copy, N: AstNode> InFileWrapper<FileId, &N> {
204250
}
205251

206252
// region:specific impls
207-
impl<SN: Borrow<SyntaxNode>> InRealFile<SN> {
208-
pub fn file_range(&self) -> FileRange {
209-
FileRange { file_id: self.file_id, range: self.value.borrow().text_range() }
253+
impl<FileId: Copy, SN: Borrow<SyntaxNode>> InFileWrapper<FileId, SN> {
254+
pub fn file_range(&self) -> FileRangeWrapper<FileId> {
255+
FileRangeWrapper { file_id: self.file_id, range: self.value.borrow().text_range() }
210256
}
211257
}
212258

crates/hir-expand/src/lib.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,10 @@ impl HirFileId {
392392
}
393393
}
394394

395+
pub fn call_node(self, db: &dyn ExpandDatabase) -> Option<InFile<SyntaxNode>> {
396+
Some(db.lookup_intern_macro_call(self.macro_file()?).to_node(db))
397+
}
398+
395399
pub fn as_builtin_derive_attr_node(
396400
&self,
397401
db: &dyn ExpandDatabase,
@@ -848,7 +852,10 @@ impl ExpansionInfo {
848852
map_node_range_up(db, &self.exp_map, range)
849853
}
850854

851-
/// Maps up the text range out of the expansion into is macro call.
855+
/// Maps up the text range out of the expansion into its macro call.
856+
///
857+
/// Note that this may return multiple ranges as we lose the precise association between input to output
858+
/// and as such we may consider inputs that are unrelated.
852859
pub fn map_range_up_once(
853860
&self,
854861
db: &dyn ExpandDatabase,
@@ -864,11 +871,10 @@ impl ExpansionInfo {
864871
InFile { file_id, value: smallvec::smallvec![span.range + anchor_offset] }
865872
}
866873
SpanMap::ExpansionSpanMap(arg_map) => {
867-
let arg_range = self
868-
.arg
869-
.value
870-
.as_ref()
871-
.map_or_else(|| TextRange::empty(TextSize::from(0)), |it| it.text_range());
874+
let Some(arg_node) = &self.arg.value else {
875+
return InFile::new(self.arg.file_id, smallvec::smallvec![]);
876+
};
877+
let arg_range = arg_node.text_range();
872878
InFile::new(
873879
self.arg.file_id,
874880
arg_map

crates/hir-expand/src/prettify_macro_expansion_.rs

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,42 +20,46 @@ pub fn prettify_macro_expansion(
2020
let span_offset = syn.text_range().start();
2121
let target_crate = target_crate_id.data(db);
2222
let mut syntax_ctx_id_to_dollar_crate_replacement = FxHashMap::default();
23-
syntax_bridge::prettify_macro_expansion::prettify_macro_expansion(syn, &mut |dollar_crate| {
24-
let ctx = span_map.span_at(dollar_crate.text_range().start() + span_offset).ctx;
25-
let replacement =
26-
syntax_ctx_id_to_dollar_crate_replacement.entry(ctx).or_insert_with(|| {
27-
let macro_call_id =
28-
ctx.outer_expn(db).expect("`$crate` cannot come from `SyntaxContextId::ROOT`");
29-
let macro_call = db.lookup_intern_macro_call(macro_call_id.into());
30-
let macro_def_crate = macro_call.def.krate;
31-
// First, if this is the same crate as the macro, nothing will work but `crate`.
32-
// If not, if the target trait has the macro's crate as a dependency, using the dependency name
33-
// will work in inserted code and match the user's expectation.
34-
// If not, the crate's display name is what the dependency name is likely to be once such dependency
35-
// is inserted, and also understandable to the user.
36-
// Lastly, if nothing else found, resort to leaving `$crate`.
37-
if target_crate_id == macro_def_crate {
38-
make::tokens::crate_kw()
39-
} else if let Some(dep) =
40-
target_crate.dependencies.iter().find(|dep| dep.crate_id == macro_def_crate)
41-
{
42-
make::tokens::ident(dep.name.as_str())
43-
} else if let Some(crate_name) = &macro_def_crate.extra_data(db).display_name {
44-
make::tokens::ident(crate_name.crate_name().as_str())
45-
} else {
46-
return dollar_crate.clone();
47-
}
48-
});
49-
if replacement.text() == "$crate" {
50-
// The parent may have many children, and looking for the token may yield incorrect results.
51-
return dollar_crate.clone();
52-
}
53-
// We need to `clone_subtree()` but rowan doesn't provide such operation for tokens.
54-
let parent = replacement.parent().unwrap().clone_subtree().clone_for_update();
55-
parent
56-
.children_with_tokens()
57-
.filter_map(NodeOrToken::into_token)
58-
.find(|it| it.kind() == replacement.kind())
59-
.unwrap()
60-
})
23+
syntax_bridge::prettify_macro_expansion::prettify_macro_expansion(
24+
syn,
25+
&mut |dollar_crate| {
26+
let ctx = span_map.span_at(dollar_crate.text_range().start() + span_offset).ctx;
27+
let replacement =
28+
syntax_ctx_id_to_dollar_crate_replacement.entry(ctx).or_insert_with(|| {
29+
let macro_call_id = ctx
30+
.outer_expn(db)
31+
.expect("`$crate` cannot come from `SyntaxContextId::ROOT`");
32+
let macro_call = db.lookup_intern_macro_call(macro_call_id.into());
33+
let macro_def_crate = macro_call.def.krate;
34+
// First, if this is the same crate as the macro, nothing will work but `crate`.
35+
// If not, if the target trait has the macro's crate as a dependency, using the dependency name
36+
// will work in inserted code and match the user's expectation.
37+
// If not, the crate's display name is what the dependency name is likely to be once such dependency
38+
// is inserted, and also understandable to the user.
39+
// Lastly, if nothing else found, resort to leaving `$crate`.
40+
if target_crate_id == macro_def_crate {
41+
make::tokens::crate_kw()
42+
} else if let Some(dep) =
43+
target_crate.dependencies.iter().find(|dep| dep.crate_id == macro_def_crate)
44+
{
45+
make::tokens::ident(dep.name.as_str())
46+
} else if let Some(crate_name) = &macro_def_crate.extra_data(db).display_name {
47+
make::tokens::ident(crate_name.crate_name().as_str())
48+
} else {
49+
return dollar_crate.clone();
50+
}
51+
});
52+
if replacement.text() == "$crate" {
53+
// The parent may have many children, and looking for the token may yield incorrect results.
54+
return None;
55+
}
56+
// We need to `clone_subtree()` but rowan doesn't provide such operation for tokens.
57+
let parent = replacement.parent().unwrap().clone_subtree().clone_for_update();
58+
parent
59+
.children_with_tokens()
60+
.filter_map(NodeOrToken::into_token)
61+
.find(|it| it.kind() == replacement.kind())
62+
},
63+
|_| (),
64+
)
6165
}

crates/mbe/src/tests.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ fn check_(
7474
"{}",
7575
syntax_bridge::prettify_macro_expansion::prettify_macro_expansion(
7676
node.syntax_node(),
77-
&mut |it| it.clone()
77+
&mut |_| None,
78+
|_| ()
7879
)
7980
);
8081
expect.assert_eq(&expect_res);

crates/span/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,10 @@ pub struct EditionedFileId(u32);
112112

113113
impl fmt::Debug for EditionedFileId {
114114
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115-
f.debug_tuple("EditionedFileId").field(&self.file_id()).field(&self.edition()).finish()
115+
f.debug_tuple("EditionedFileId")
116+
.field(&self.file_id().index())
117+
.field(&self.edition())
118+
.finish()
116119
}
117120
}
118121

crates/syntax-bridge/src/prettify_macro_expansion.rs

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ use syntax::{
77
ted::{self, Position},
88
};
99

10+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11+
pub enum PrettifyWsKind {
12+
Space,
13+
Indent(usize),
14+
Newline,
15+
}
16+
1017
/// Renders a [`SyntaxNode`] with whitespace inserted between tokens that require them.
1118
///
1219
/// This is an internal API that is only exported because `mbe` needs it for tests and cannot depend
@@ -15,7 +22,8 @@ use syntax::{
1522
#[deprecated = "use `hir_expand::prettify_macro_expansion()` instead"]
1623
pub fn prettify_macro_expansion(
1724
syn: SyntaxNode,
18-
dollar_crate_replacement: &mut dyn FnMut(&SyntaxToken) -> SyntaxToken,
25+
dollar_crate_replacement: &mut dyn FnMut(&SyntaxToken) -> Option<SyntaxToken>,
26+
inspect_mods: impl FnOnce(&[(Position, PrettifyWsKind)]),
1927
) -> SyntaxNode {
2028
let mut indent = 0;
2129
let mut last: Option<SyntaxKind> = None;
@@ -27,14 +35,12 @@ pub fn prettify_macro_expansion(
2735
let after = Position::after;
2836

2937
let do_indent = |pos: fn(_) -> Position, token: &SyntaxToken, indent| {
30-
(pos(token.clone()), make::tokens::whitespace(&" ".repeat(4 * indent)))
31-
};
32-
let do_ws = |pos: fn(_) -> Position, token: &SyntaxToken| {
33-
(pos(token.clone()), make::tokens::single_space())
34-
};
35-
let do_nl = |pos: fn(_) -> Position, token: &SyntaxToken| {
36-
(pos(token.clone()), make::tokens::single_newline())
38+
(pos(token.clone()), PrettifyWsKind::Indent(indent))
3739
};
40+
let do_ws =
41+
|pos: fn(_) -> Position, token: &SyntaxToken| (pos(token.clone()), PrettifyWsKind::Space);
42+
let do_nl =
43+
|pos: fn(_) -> Position, token: &SyntaxToken| (pos(token.clone()), PrettifyWsKind::Newline);
3844

3945
for event in syn.preorder_with_tokens() {
4046
let token = match event {
@@ -46,20 +52,19 @@ pub fn prettify_macro_expansion(
4652
) =>
4753
{
4854
if indent > 0 {
49-
mods.push((
50-
Position::after(node.clone()),
51-
make::tokens::whitespace(&" ".repeat(4 * indent)),
52-
));
55+
mods.push((Position::after(node.clone()), PrettifyWsKind::Indent(indent)));
5356
}
5457
if node.parent().is_some() {
55-
mods.push((Position::after(node), make::tokens::single_newline()));
58+
mods.push((Position::after(node), PrettifyWsKind::Newline));
5659
}
5760
continue;
5861
}
5962
_ => continue,
6063
};
6164
if token.kind() == SyntaxKind::IDENT && token.text() == "$crate" {
62-
dollar_crate_replacements.push((token.clone(), dollar_crate_replacement(&token)));
65+
if let Some(replacement) = dollar_crate_replacement(&token) {
66+
dollar_crate_replacements.push((token.clone(), replacement));
67+
}
6368
}
6469
let tok = &token;
6570

@@ -129,8 +134,16 @@ pub fn prettify_macro_expansion(
129134
last = Some(tok.kind());
130135
}
131136

137+
inspect_mods(&mods);
132138
for (pos, insert) in mods {
133-
ted::insert(pos, insert);
139+
ted::insert_raw(
140+
pos,
141+
match insert {
142+
PrettifyWsKind::Space => make::tokens::single_space(),
143+
PrettifyWsKind::Indent(indent) => make::tokens::whitespace(&" ".repeat(4 * indent)),
144+
PrettifyWsKind::Newline => make::tokens::single_newline(),
145+
},
146+
);
134147
}
135148
for (old, new) in dollar_crate_replacements {
136149
ted::replace(old, new);

0 commit comments

Comments
 (0)