mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-11-01 04:18:20 +00:00
Add some more hir_expand::files conversions
This commit is contained in:
parent
e65dddaf59
commit
f0e39c77cc
6 changed files with 137 additions and 64 deletions
|
|
@ -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() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) = ¯o_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) = ¯o_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())
|
||||
},
|
||||
|_| (),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue