diff --git a/Cargo.lock b/Cargo.lock index 87150226ecd..92a729c41c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,7 +79,6 @@ dependencies = [ "syntax", "test-utils", "triomphe", - "tt", "vfs", ] diff --git a/crates/base-db/Cargo.toml b/crates/base-db/Cargo.toml index 6558bdcaf72..a8ff97bdedd 100644 --- a/crates/base-db/Cargo.toml +++ b/crates/base-db/Cargo.toml @@ -23,6 +23,5 @@ profile.workspace = true stdx.workspace = true syntax.workspace = true test-utils.workspace = true -tt.workspace = true vfs.workspace = true span.workspace = true diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs index 23c7e1071ae..dab9d5d5609 100644 --- a/crates/hir-expand/src/db.rs +++ b/crates/hir-expand/src/db.rs @@ -170,7 +170,20 @@ pub fn span_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> SpanMap { } pub fn real_span_map(db: &dyn ExpandDatabase, file_id: FileId) -> Arc { - Arc::new(RealSpanMap::from_file(db, file_id)) + use syntax::ast::HasModuleItem; + let mut pairs = vec![(syntax::TextSize::new(0), span::ROOT_ERASED_FILE_AST_ID)]; + let ast_id_map = db.ast_id_map(file_id.into()); + let tree = db.parse(file_id).tree(); + pairs.extend( + tree.items() + .map(|item| (item.syntax().text_range().start(), ast_id_map.ast_id(&item).erase())), + ); + + Arc::new(RealSpanMap::from_file( + file_id, + pairs.into_boxed_slice(), + tree.syntax().text_range().end(), + )) } /// This expands the given macro call, but with different arguments. This is diff --git a/crates/hir-expand/src/hygiene.rs b/crates/hir-expand/src/hygiene.rs index fb9db3333f5..5ab8581aead 100644 --- a/crates/hir-expand/src/hygiene.rs +++ b/crates/hir-expand/src/hygiene.rs @@ -2,6 +2,9 @@ //! //! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at //! this moment, this is horribly incomplete and handles only `$crate`. + +// FIXME: Consider moving this into the span crate. + use std::iter; use span::{MacroCallId, Span, SyntaxContextId}; diff --git a/crates/hir-expand/src/quote.rs b/crates/hir-expand/src/quote.rs index 2684bd80c7d..7c247246906 100644 --- a/crates/hir-expand/src/quote.rs +++ b/crates/hir-expand/src/quote.rs @@ -259,8 +259,8 @@ fn test_quote_hash_token_tree() { assert_eq!(quoted.to_string(), "hello"); let t = format!("{quoted:?}"); expect![[r#" - SUBTREE $$ Span { range: 0..0, anchor: SpanAnchor(FileId(937550), 0), ctx: SyntaxContextId(0) } Span { range: 0..0, anchor: SpanAnchor(FileId(937550), 0), ctx: SyntaxContextId(0) } - IDENT hello Span { range: 0..0, anchor: SpanAnchor(FileId(937550), 0), ctx: SyntaxContextId(0) }"#]].assert_eq(&t); + SUBTREE $$ SpanData { range: 0..0, anchor: SpanAnchor(FileId(937550), 0), ctx: SyntaxContextId(0) } SpanData { range: 0..0, anchor: SpanAnchor(FileId(937550), 0), ctx: SyntaxContextId(0) } + IDENT hello SpanData { range: 0..0, anchor: SpanAnchor(FileId(937550), 0), ctx: SyntaxContextId(0) }"#]].assert_eq(&t); } #[test] diff --git a/crates/hir-expand/src/span_map.rs b/crates/hir-expand/src/span_map.rs index 386063155dd..f9763cd8866 100644 --- a/crates/hir-expand/src/span_map.rs +++ b/crates/hir-expand/src/span_map.rs @@ -1,14 +1,9 @@ -//! Spanmaps allow turning absolute ranges into relative ranges for incrementality purposes as well -//! as associating spans with text ranges in a particular file. - -// FIXME: Consider moving this into the span crate - -use base_db::FileId; -use span::{ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; -use syntax::{ast::HasModuleItem, AstNode, TextRange, TextSize}; +//! Span maps for real files and macro expansions. +use span::Span; +use syntax::TextRange; use triomphe::Arc; -use crate::db::ExpandDatabase; +pub use span::RealSpanMap; pub type ExpansionSpanMap = span::SpanMap; @@ -39,11 +34,6 @@ fn span_for(&self, range: TextRange) -> Span { self.span_for_range(range) } } -impl mbe::SpanMapper for RealSpanMap { - fn span_for(&self, range: TextRange) -> Span { - self.span_for_range(range) - } -} impl SpanMap { pub fn span_for_range(&self, range: TextRange) -> Span { @@ -69,57 +59,3 @@ pub fn span_for_range(self, range: TextRange) -> Span { } } } - -#[derive(PartialEq, Eq, Hash, Debug)] -pub struct RealSpanMap { - file_id: FileId, - /// Invariant: Sorted vec over TextSize - // FIXME: SortedVec<(TextSize, ErasedFileAstId)>? - pairs: Box<[(TextSize, ErasedFileAstId)]>, - end: TextSize, -} - -impl RealSpanMap { - /// Creates a real file span map that returns absolute ranges (relative ranges to the root ast id). - pub fn absolute(file_id: FileId) -> Self { - RealSpanMap { - file_id, - pairs: Box::from([(TextSize::new(0), ROOT_ERASED_FILE_AST_ID)]), - end: TextSize::new(!0), - } - } - - pub fn from_file(db: &dyn ExpandDatabase, file_id: FileId) -> Self { - let mut pairs = vec![(TextSize::new(0), ROOT_ERASED_FILE_AST_ID)]; - let ast_id_map = db.ast_id_map(file_id.into()); - let tree = db.parse(file_id).tree(); - pairs - .extend(tree.items().map(|item| { - (item.syntax().text_range().start(), ast_id_map.ast_id(&item).erase()) - })); - RealSpanMap { - file_id, - pairs: pairs.into_boxed_slice(), - end: tree.syntax().text_range().end(), - } - } - - pub fn span_for_range(&self, range: TextRange) -> Span { - assert!( - range.end() <= self.end, - "range {range:?} goes beyond the end of the file {:?}", - self.end - ); - let start = range.start(); - let idx = self - .pairs - .binary_search_by(|&(it, _)| it.cmp(&start).then(std::cmp::Ordering::Less)) - .unwrap_err(); - let (offset, ast_id) = self.pairs[idx - 1]; - Span { - range: range - offset, - anchor: SpanAnchor { file_id: self.file_id, ast_id }, - ctx: SyntaxContextId::ROOT, - } - } -} diff --git a/crates/span/src/lib.rs b/crates/span/src/lib.rs index c8c48c9f1f4..d9f20e18c4a 100644 --- a/crates/span/src/lib.rs +++ b/crates/span/src/lib.rs @@ -8,7 +8,7 @@ mod map; -pub use crate::map::SpanMap; +pub use crate::map::{RealSpanMap, SpanMap}; pub use syntax::{TextRange, TextSize}; pub use vfs::FileId; diff --git a/crates/span/src/map.rs b/crates/span/src/map.rs index e69d003c078..d69df91b63e 100644 --- a/crates/span/src/map.rs +++ b/crates/span/src/map.rs @@ -5,6 +5,9 @@ use stdx::{always, itertools::Itertools}; use syntax::{TextRange, TextSize}; +use vfs::FileId; + +use crate::{ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; /// Maps absolute text ranges for the corresponding file to the relevant span data. #[derive(Debug, PartialEq, Eq, Clone, Hash)] @@ -79,3 +82,50 @@ pub fn iter(&self) -> impl Iterator + '_ { self.spans.iter().copied() } } + +#[derive(PartialEq, Eq, Hash, Debug)] +pub struct RealSpanMap { + file_id: FileId, + /// Invariant: Sorted vec over TextSize + // FIXME: SortedVec<(TextSize, ErasedFileAstId)>? + pairs: Box<[(TextSize, ErasedFileAstId)]>, + end: TextSize, +} + +impl RealSpanMap { + /// Creates a real file span map that returns absolute ranges (relative ranges to the root ast id). + pub fn absolute(file_id: FileId) -> Self { + RealSpanMap { + file_id, + pairs: Box::from([(TextSize::new(0), ROOT_ERASED_FILE_AST_ID)]), + end: TextSize::new(!0), + } + } + + pub fn from_file( + file_id: FileId, + pairs: Box<[(TextSize, ErasedFileAstId)]>, + end: TextSize, + ) -> Self { + Self { file_id, pairs, end } + } + + pub fn span_for_range(&self, range: TextRange) -> Span { + assert!( + range.end() <= self.end, + "range {range:?} goes beyond the end of the file {:?}", + self.end + ); + let start = range.start(); + let idx = self + .pairs + .binary_search_by(|&(it, _)| it.cmp(&start).then(std::cmp::Ordering::Less)) + .unwrap_err(); + let (offset, ast_id) = self.pairs[idx - 1]; + Span { + range: range - offset, + anchor: SpanAnchor { file_id: self.file_id, ast_id }, + ctx: SyntaxContextId::ROOT, + } + } +}