diff --git a/crates/proc-macro-srv/src/server/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server/rust_analyzer_span.rs index d8648da604..adb7ff1bdf 100644 --- a/crates/proc-macro-srv/src/server/rust_analyzer_span.rs +++ b/crates/proc-macro-srv/src/server/rust_analyzer_span.rs @@ -4,6 +4,7 @@ use std::{ ops::{Bound, Range}, }; +use ::tt::{TextRange, TextSize}; use proc_macro::bridge::{self, server}; use span::Span; @@ -241,11 +242,11 @@ impl server::Span for RaSpanServer { SourceFile {} } fn save_span(&mut self, _span: Self::Span) -> usize { - // FIXME stub + // FIXME stub, requires builtin quote! implementation 0 } fn recover_proc_macro_span(&mut self, _id: usize) -> Self::Span { - // FIXME stub + // FIXME stub, requires builtin quote! implementation self.call_site } /// Recent feature, not yet in the proc_macro @@ -289,32 +290,64 @@ impl server::Span for RaSpanServer { fn subspan( &mut self, span: Self::Span, - _start: Bound, - _end: Bound, + start: Bound, + end: Bound, ) -> Option { - // Just return the span again, because some macros will unwrap the result. - Some(span) - } - fn resolved_at(&mut self, _span: Self::Span, _at: Self::Span) -> Self::Span { - // FIXME handle span - self.call_site + // FIXME requires db to resolve the ast id, THIS IS NOT INCREMENTAL as it works on absolute + // ranges + let length = span.range.len().into(); + + let start: u32 = match start { + Bound::Included(lo) => lo, + Bound::Excluded(lo) => lo.checked_add(1)?, + Bound::Unbounded => 0, + } + .try_into() + .ok()?; + + let end: u32 = match end { + Bound::Included(hi) => hi.checked_add(1)?, + Bound::Excluded(hi) => hi, + Bound::Unbounded => span.range.len().into(), + } + .try_into() + .ok()?; + + // Bounds check the values, preventing addition overflow and OOB spans. + let span_start = span.range.start().into(); + if (u32::MAX - start) < span_start + || (u32::MAX - end) < span_start + || start >= end + || end > length + { + return None; + } + + Some(Span { + range: TextRange::new(TextSize::from(start), TextSize::from(end)) + span.range.start(), + ..span + }) } - fn end(&mut self, _self_: Self::Span) -> Self::Span { - self.call_site + fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span { + Span { ctx: at.ctx, ..span } } - fn start(&mut self, _self_: Self::Span) -> Self::Span { - self.call_site + fn end(&mut self, span: Self::Span) -> Self::Span { + Span { range: TextRange::empty(span.range.end()), ..span } + } + + fn start(&mut self, span: Self::Span) -> Self::Span { + Span { range: TextRange::empty(span.range.start()), ..span } } fn line(&mut self, _span: Self::Span) -> usize { - // FIXME handle line + // FIXME requires db to resolve line index, THIS IS NOT INCREMENTAL 0 } fn column(&mut self, _span: Self::Span) -> usize { - // FIXME handle column + // FIXME requires db to resolve line index, THIS IS NOT INCREMENTAL 0 } } diff --git a/crates/proc-macro-srv/src/tests/mod.rs b/crates/proc-macro-srv/src/tests/mod.rs index 2320a04cf1..87d832cc76 100644 --- a/crates/proc-macro-srv/src/tests/mod.rs +++ b/crates/proc-macro-srv/src/tests/mod.rs @@ -105,6 +105,24 @@ fn test_fn_like_fn_like_span_join() { ); } +#[test] +fn test_fn_like_fn_like_span_ops() { + assert_expand( + "fn_like_span_ops", + "set_def_site resolved_at_def_site start_span", + expect![[r#" + SUBTREE $$ 1 1 + IDENT set_def_site 0 + IDENT resolved_at_def_site 1 + IDENT start_span 1"#]], + expect![[r#" + SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } + IDENT set_def_site SpanData { range: 0..150, anchor: SpanAnchor(FileId(41), 1), ctx: SyntaxContextId(0) } + IDENT resolved_at_def_site SpanData { range: 13..33, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } + IDENT start_span SpanData { range: 34..34, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"#]], + ); +} + #[test] fn test_fn_like_mk_literals() { assert_expand( @@ -218,6 +236,7 @@ fn list_test_macros() { fn_like_mk_literals [FuncLike] fn_like_mk_idents [FuncLike] fn_like_span_join [FuncLike] + fn_like_span_ops [FuncLike] attr_noop [Attr] attr_panic [Attr] attr_error [Attr] diff --git a/crates/proc-macro-test/imp/src/lib.rs b/crates/proc-macro-test/imp/src/lib.rs index d0f73dca32..d9018b1b87 100644 --- a/crates/proc-macro-test/imp/src/lib.rs +++ b/crates/proc-macro-test/imp/src/lib.rs @@ -1,7 +1,7 @@ //! Exports a few trivial procedural macros for testing. #![warn(rust_2018_idioms, unused_lifetimes)] -#![feature(proc_macro_span)] +#![feature(proc_macro_span, proc_macro_def_site)] use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree}; @@ -61,6 +61,18 @@ pub fn fn_like_span_join(args: TokenStream) -> TokenStream { ))) } +#[proc_macro] +pub fn fn_like_span_ops(args: TokenStream) -> TokenStream { + let args = &mut args.into_iter(); + let mut first = args.next().unwrap(); + first.set_span(Span::def_site()); + let mut second = args.next().unwrap(); + second.set_span(second.span().resolved_at(Span::def_site())); + let mut third = args.next().unwrap(); + third.set_span(third.span().start()); + TokenStream::from_iter(vec![first, second, third]) +} + #[proc_macro_attribute] pub fn attr_noop(_args: TokenStream, item: TokenStream) -> TokenStream { item