mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 20:09:01 +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()) | ||||
|         }, | ||||
|         |_| (), | ||||
|     ) | ||||
| } | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
|  | @ -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() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -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); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lukas Wirth
						Lukas Wirth