Unnamed repository; edit this file 'description' to name the repository.
Add some more `hir_expand::files` conversions
Lukas Wirth 11 months ago
parent e65ddda · commit f0e39c7
-rw-r--r--crates/hir-expand/src/files.rs52
-rw-r--r--crates/hir-expand/src/lib.rs18
-rw-r--r--crates/hir-expand/src/prettify_macro_expansion_.rs80
-rw-r--r--crates/mbe/src/tests.rs3
-rw-r--r--crates/span/src/lib.rs5
-rw-r--r--crates/syntax-bridge/src/prettify_macro_expansion.rs43
6 files changed, 137 insertions, 64 deletions
diff --git a/crates/hir-expand/src/files.rs b/crates/hir-expand/src/files.rs
index 321ee8feb9..8024823cbc 100644
--- a/crates/hir-expand/src/files.rs
+++ b/crates/hir-expand/src/files.rs
@@ -42,6 +42,49 @@ impl FilePosition {
FilePositionWrapper { file_id: self.file_id.file_id(db), offset: self.offset }
}
}
+
+impl From<FileRange> for HirFileRange {
+ fn from(value: FileRange) -> Self {
+ HirFileRange { file_id: value.file_id.into(), range: value.range }
+ }
+}
+
+impl From<FilePosition> for HirFilePosition {
+ fn from(value: FilePosition) -> Self {
+ HirFilePosition { file_id: value.file_id.into(), offset: value.offset }
+ }
+}
+
+impl FilePositionWrapper<span::FileId> {
+ pub fn with_edition(self, db: &dyn ExpandDatabase, edition: span::Edition) -> FilePosition {
+ FilePositionWrapper {
+ file_id: EditionedFileId::new(db, self.file_id, edition),
+ offset: self.offset,
+ }
+ }
+}
+
+impl FileRangeWrapper<span::FileId> {
+ pub fn with_edition(self, db: &dyn ExpandDatabase, edition: span::Edition) -> FileRange {
+ FileRangeWrapper {
+ file_id: EditionedFileId::new(db, self.file_id, edition),
+ range: self.range,
+ }
+ }
+}
+
+impl<T> InFileWrapper<span::FileId, T> {
+ pub fn with_edition(self, db: &dyn ExpandDatabase, edition: span::Edition) -> InRealFile<T> {
+ InRealFile { file_id: EditionedFileId::new(db, self.file_id, edition), value: self.value }
+ }
+}
+
+impl HirFileRange {
+ pub fn file_range(self) -> Option<FileRange> {
+ Some(FileRange { file_id: self.file_id.file_id()?, range: self.range })
+ }
+}
+
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct FileRangeWrapper<FileKind> {
pub file_id: FileKind,
@@ -194,6 +237,9 @@ impl<FileId: Copy, N: AstNode> InFileWrapper<FileId, N> {
pub fn syntax(&self) -> InFileWrapper<FileId, &SyntaxNode> {
self.with_value(self.value.syntax())
}
+ pub fn node_file_range(&self) -> FileRangeWrapper<FileId> {
+ FileRangeWrapper { file_id: self.file_id, range: self.value.syntax().text_range() }
+ }
}
impl<FileId: Copy, N: AstNode> InFileWrapper<FileId, &N> {
@@ -204,9 +250,9 @@ impl<FileId: Copy, N: AstNode> InFileWrapper<FileId, &N> {
}
// region:specific impls
-impl<SN: Borrow<SyntaxNode>> InRealFile<SN> {
- pub fn file_range(&self) -> FileRange {
- FileRange { file_id: self.file_id, range: self.value.borrow().text_range() }
+impl<FileId: Copy, SN: Borrow<SyntaxNode>> InFileWrapper<FileId, SN> {
+ pub fn file_range(&self) -> FileRangeWrapper<FileId> {
+ FileRangeWrapper { file_id: self.file_id, range: self.value.borrow().text_range() }
}
}
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index d844d8f41e..6ecac1463f 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -392,6 +392,10 @@ impl HirFileId {
}
}
+ pub fn call_node(self, db: &dyn ExpandDatabase) -> Option<InFile<SyntaxNode>> {
+ Some(db.lookup_intern_macro_call(self.macro_file()?).to_node(db))
+ }
+
pub fn as_builtin_derive_attr_node(
&self,
db: &dyn ExpandDatabase,
@@ -848,7 +852,10 @@ impl ExpansionInfo {
map_node_range_up(db, &self.exp_map, range)
}
- /// Maps up the text range out of the expansion into is macro call.
+ /// Maps up the text range out of the expansion into its macro call.
+ ///
+ /// Note that this may return multiple ranges as we lose the precise association between input to output
+ /// and as such we may consider inputs that are unrelated.
pub fn map_range_up_once(
&self,
db: &dyn ExpandDatabase,
@@ -864,11 +871,10 @@ impl ExpansionInfo {
InFile { file_id, value: smallvec::smallvec![span.range + anchor_offset] }
}
SpanMap::ExpansionSpanMap(arg_map) => {
- let arg_range = self
- .arg
- .value
- .as_ref()
- .map_or_else(|| TextRange::empty(TextSize::from(0)), |it| it.text_range());
+ let Some(arg_node) = &self.arg.value else {
+ return InFile::new(self.arg.file_id, smallvec::smallvec![]);
+ };
+ let arg_range = arg_node.text_range();
InFile::new(
self.arg.file_id,
arg_map
diff --git a/crates/hir-expand/src/prettify_macro_expansion_.rs b/crates/hir-expand/src/prettify_macro_expansion_.rs
index 11cc434c2d..6134c3a36b 100644
--- a/crates/hir-expand/src/prettify_macro_expansion_.rs
+++ b/crates/hir-expand/src/prettify_macro_expansion_.rs
@@ -20,42 +20,46 @@ pub fn prettify_macro_expansion(
let span_offset = syn.text_range().start();
let target_crate = target_crate_id.data(db);
let mut syntax_ctx_id_to_dollar_crate_replacement = FxHashMap::default();
- syntax_bridge::prettify_macro_expansion::prettify_macro_expansion(syn, &mut |dollar_crate| {
- let ctx = span_map.span_at(dollar_crate.text_range().start() + span_offset).ctx;
- let replacement =
- syntax_ctx_id_to_dollar_crate_replacement.entry(ctx).or_insert_with(|| {
- let macro_call_id =
- ctx.outer_expn(db).expect("`$crate` cannot come from `SyntaxContextId::ROOT`");
- let macro_call = db.lookup_intern_macro_call(macro_call_id.into());
- let macro_def_crate = macro_call.def.krate;
- // First, if this is the same crate as the macro, nothing will work but `crate`.
- // If not, if the target trait has the macro's crate as a dependency, using the dependency name
- // will work in inserted code and match the user's expectation.
- // If not, the crate's display name is what the dependency name is likely to be once such dependency
- // is inserted, and also understandable to the user.
- // Lastly, if nothing else found, resort to leaving `$crate`.
- if target_crate_id == macro_def_crate {
- make::tokens::crate_kw()
- } else if let Some(dep) =
- target_crate.dependencies.iter().find(|dep| dep.crate_id == macro_def_crate)
- {
- make::tokens::ident(dep.name.as_str())
- } else if let Some(crate_name) = &macro_def_crate.extra_data(db).display_name {
- make::tokens::ident(crate_name.crate_name().as_str())
- } else {
- return dollar_crate.clone();
- }
- });
- if replacement.text() == "$crate" {
- // The parent may have many children, and looking for the token may yield incorrect results.
- return dollar_crate.clone();
- }
- // We need to `clone_subtree()` but rowan doesn't provide such operation for tokens.
- let parent = replacement.parent().unwrap().clone_subtree().clone_for_update();
- parent
- .children_with_tokens()
- .filter_map(NodeOrToken::into_token)
- .find(|it| it.kind() == replacement.kind())
- .unwrap()
- })
+ syntax_bridge::prettify_macro_expansion::prettify_macro_expansion(
+ syn,
+ &mut |dollar_crate| {
+ let ctx = span_map.span_at(dollar_crate.text_range().start() + span_offset).ctx;
+ let replacement =
+ syntax_ctx_id_to_dollar_crate_replacement.entry(ctx).or_insert_with(|| {
+ let macro_call_id = ctx
+ .outer_expn(db)
+ .expect("`$crate` cannot come from `SyntaxContextId::ROOT`");
+ let macro_call = db.lookup_intern_macro_call(macro_call_id.into());
+ let macro_def_crate = macro_call.def.krate;
+ // First, if this is the same crate as the macro, nothing will work but `crate`.
+ // If not, if the target trait has the macro's crate as a dependency, using the dependency name
+ // will work in inserted code and match the user's expectation.
+ // If not, the crate's display name is what the dependency name is likely to be once such dependency
+ // is inserted, and also understandable to the user.
+ // Lastly, if nothing else found, resort to leaving `$crate`.
+ if target_crate_id == macro_def_crate {
+ make::tokens::crate_kw()
+ } else if let Some(dep) =
+ target_crate.dependencies.iter().find(|dep| dep.crate_id == macro_def_crate)
+ {
+ make::tokens::ident(dep.name.as_str())
+ } else if let Some(crate_name) = &macro_def_crate.extra_data(db).display_name {
+ make::tokens::ident(crate_name.crate_name().as_str())
+ } else {
+ return dollar_crate.clone();
+ }
+ });
+ if replacement.text() == "$crate" {
+ // The parent may have many children, and looking for the token may yield incorrect results.
+ return None;
+ }
+ // We need to `clone_subtree()` but rowan doesn't provide such operation for tokens.
+ let parent = replacement.parent().unwrap().clone_subtree().clone_for_update();
+ parent
+ .children_with_tokens()
+ .filter_map(NodeOrToken::into_token)
+ .find(|it| it.kind() == replacement.kind())
+ },
+ |_| (),
+ )
}
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index 3369dfff28..769455faac 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -74,7 +74,8 @@ fn check_(
"{}",
syntax_bridge::prettify_macro_expansion::prettify_macro_expansion(
node.syntax_node(),
- &mut |it| it.clone()
+ &mut |_| None,
+ |_| ()
)
);
expect.assert_eq(&expect_res);
diff --git a/crates/span/src/lib.rs b/crates/span/src/lib.rs
index 54f90908f3..f81648ac42 100644
--- a/crates/span/src/lib.rs
+++ b/crates/span/src/lib.rs
@@ -112,7 +112,10 @@ pub struct EditionedFileId(u32);
impl fmt::Debug for EditionedFileId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("EditionedFileId").field(&self.file_id()).field(&self.edition()).finish()
+ f.debug_tuple("EditionedFileId")
+ .field(&self.file_id().index())
+ .field(&self.edition())
+ .finish()
}
}
diff --git a/crates/syntax-bridge/src/prettify_macro_expansion.rs b/crates/syntax-bridge/src/prettify_macro_expansion.rs
index e815e07d80..0a5c8df0d0 100644
--- a/crates/syntax-bridge/src/prettify_macro_expansion.rs
+++ b/crates/syntax-bridge/src/prettify_macro_expansion.rs
@@ -7,6 +7,13 @@ use syntax::{
ted::{self, Position},
};
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum PrettifyWsKind {
+ Space,
+ Indent(usize),
+ Newline,
+}
+
/// Renders a [`SyntaxNode`] with whitespace inserted between tokens that require them.
///
/// This is an internal API that is only exported because `mbe` needs it for tests and cannot depend
@@ -15,7 +22,8 @@ use syntax::{
#[deprecated = "use `hir_expand::prettify_macro_expansion()` instead"]
pub fn prettify_macro_expansion(
syn: SyntaxNode,
- dollar_crate_replacement: &mut dyn FnMut(&SyntaxToken) -> SyntaxToken,
+ dollar_crate_replacement: &mut dyn FnMut(&SyntaxToken) -> Option<SyntaxToken>,
+ inspect_mods: impl FnOnce(&[(Position, PrettifyWsKind)]),
) -> SyntaxNode {
let mut indent = 0;
let mut last: Option<SyntaxKind> = None;
@@ -27,14 +35,12 @@ pub fn prettify_macro_expansion(
let after = Position::after;
let do_indent = |pos: fn(_) -> Position, token: &SyntaxToken, indent| {
- (pos(token.clone()), make::tokens::whitespace(&" ".repeat(4 * indent)))
- };
- let do_ws = |pos: fn(_) -> Position, token: &SyntaxToken| {
- (pos(token.clone()), make::tokens::single_space())
- };
- let do_nl = |pos: fn(_) -> Position, token: &SyntaxToken| {
- (pos(token.clone()), make::tokens::single_newline())
+ (pos(token.clone()), PrettifyWsKind::Indent(indent))
};
+ let do_ws =
+ |pos: fn(_) -> Position, token: &SyntaxToken| (pos(token.clone()), PrettifyWsKind::Space);
+ let do_nl =
+ |pos: fn(_) -> Position, token: &SyntaxToken| (pos(token.clone()), PrettifyWsKind::Newline);
for event in syn.preorder_with_tokens() {
let token = match event {
@@ -46,20 +52,19 @@ pub fn prettify_macro_expansion(
) =>
{
if indent > 0 {
- mods.push((
- Position::after(node.clone()),
- make::tokens::whitespace(&" ".repeat(4 * indent)),
- ));
+ mods.push((Position::after(node.clone()), PrettifyWsKind::Indent(indent)));
}
if node.parent().is_some() {
- mods.push((Position::after(node), make::tokens::single_newline()));
+ mods.push((Position::after(node), PrettifyWsKind::Newline));
}
continue;
}
_ => continue,
};
if token.kind() == SyntaxKind::IDENT && token.text() == "$crate" {
- dollar_crate_replacements.push((token.clone(), dollar_crate_replacement(&token)));
+ if let Some(replacement) = dollar_crate_replacement(&token) {
+ dollar_crate_replacements.push((token.clone(), replacement));
+ }
}
let tok = &token;
@@ -129,8 +134,16 @@ pub fn prettify_macro_expansion(
last = Some(tok.kind());
}
+ inspect_mods(&mods);
for (pos, insert) in mods {
- ted::insert(pos, insert);
+ ted::insert_raw(
+ pos,
+ match insert {
+ PrettifyWsKind::Space => make::tokens::single_space(),
+ PrettifyWsKind::Indent(indent) => make::tokens::whitespace(&" ".repeat(4 * indent)),
+ PrettifyWsKind::Newline => make::tokens::single_newline(),
+ },
+ );
}
for (old, new) in dollar_crate_replacements {
ted::replace(old, new);