mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
Add unstable Literal::subspan().
This commit is contained in:
parent
f1e2fa8f04
commit
09e7051b7e
@ -50,6 +50,7 @@ mod diagnostic;
|
||||
#[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
|
||||
pub use diagnostic::{Diagnostic, Level, MultiSpan};
|
||||
|
||||
use std::ops::{Bound, RangeBounds};
|
||||
use std::{ascii, fmt, iter};
|
||||
use std::path::PathBuf;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
@ -59,7 +60,7 @@ use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::parse::{self, token};
|
||||
use syntax::symbol::Symbol;
|
||||
use syntax::tokenstream::{self, DelimSpan};
|
||||
use syntax_pos::{Pos, FileName};
|
||||
use syntax_pos::{Pos, FileName, BytePos};
|
||||
|
||||
/// The main type provided by this crate, representing an abstract stream of
|
||||
/// tokens, or, more specifically, a sequence of token trees.
|
||||
@ -1168,6 +1169,50 @@ impl Literal {
|
||||
pub fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
|
||||
/// Returns a `Span` that is a subset of `self.span()` containing only the
|
||||
/// source bytes in range `range`. Returns `None` if the would-be trimmed
|
||||
/// span is outside the bounds of `self`.
|
||||
// FIXME(SergioBenitez): check that the byte range starts and ends at a
|
||||
// UTF-8 boundary of the source. otherwise, it's likely that a panic will
|
||||
// occur elsewhere when the source text is printed.
|
||||
// FIXME(SergioBenitez): there is no way for the user to know what
|
||||
// `self.span()` actually maps to, so this method can currently only be
|
||||
// called blindly. For example, `to_string()` for the character 'c' returns
|
||||
// "'\u{63}'"; there is no way for the user to know whether the source text
|
||||
// was 'c' or whether it was '\u{63}'.
|
||||
#[unstable(feature = "proc_macro_span", issue = "54725")]
|
||||
pub fn subspan<R: RangeBounds<usize>>(&self, range: R) -> Option<Span> {
|
||||
let inner = self.span().0;
|
||||
let length = inner.hi().to_usize() - inner.lo().to_usize();
|
||||
|
||||
let start = match range.start_bound() {
|
||||
Bound::Included(&lo) => lo,
|
||||
Bound::Excluded(&lo) => lo + 1,
|
||||
Bound::Unbounded => 0,
|
||||
};
|
||||
|
||||
let end = match range.end_bound() {
|
||||
Bound::Included(&hi) => hi + 1,
|
||||
Bound::Excluded(&hi) => hi,
|
||||
Bound::Unbounded => length,
|
||||
};
|
||||
|
||||
// Bounds check the values, preventing addition overflow and OOB spans.
|
||||
if start > u32::max_value() as usize
|
||||
|| end > u32::max_value() as usize
|
||||
|| (u32::max_value() - start as u32) < inner.lo().to_u32()
|
||||
|| (u32::max_value() - end as u32) < inner.lo().to_u32()
|
||||
|| start >= end
|
||||
|| end > length
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let new_lo = inner.lo() + BytePos::from_usize(start);
|
||||
let new_hi = inner.lo() + BytePos::from_usize(end);
|
||||
Some(Span(inner.with_lo(new_lo).with_hi(new_hi)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the literal as a string that should be losslessly convertible
|
||||
|
47
src/test/ui-fulldeps/auxiliary/subspan.rs
Normal file
47
src/test/ui-fulldeps/auxiliary/subspan.rs
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
#![feature(proc_macro_diagnostic, proc_macro_span)]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::{TokenStream, TokenTree, Span, Diagnostic};
|
||||
|
||||
fn parse(input: TokenStream) -> Result<(), Diagnostic> {
|
||||
if let Some(TokenTree::Literal(lit)) = input.into_iter().next() {
|
||||
let mut spans = vec![];
|
||||
let string = lit.to_string();
|
||||
for hi in string.matches("hi") {
|
||||
let index = hi.as_ptr() as usize - string.as_ptr() as usize;
|
||||
let subspan = lit.subspan(index..(index + hi.len())).unwrap();
|
||||
spans.push(subspan);
|
||||
}
|
||||
|
||||
if !spans.is_empty() {
|
||||
Err(Span::call_site().error("found 'hi's").span_note(spans, "here"))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
Err(Span::call_site().error("invalid input: expected string literal"))
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn subspan(input: TokenStream) -> TokenStream {
|
||||
if let Err(diag) = parse(input) {
|
||||
diag.emit();
|
||||
}
|
||||
|
||||
TokenStream::new()
|
||||
}
|
37
src/test/ui-fulldeps/subspan.rs
Normal file
37
src/test/ui-fulldeps/subspan.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// aux-build:subspan.rs
|
||||
// ignore-stage1
|
||||
|
||||
extern crate subspan;
|
||||
|
||||
use subspan::subspan;
|
||||
|
||||
// This one emits no error.
|
||||
subspan!("");
|
||||
|
||||
// Exactly one 'hi'.
|
||||
subspan!("hi"); //~ ERROR found 'hi's
|
||||
|
||||
// Now two, back to back.
|
||||
subspan!("hihi"); //~ ERROR found 'hi's
|
||||
|
||||
// Now three, back to back.
|
||||
subspan!("hihihi"); //~ ERROR found 'hi's
|
||||
|
||||
// Now several, with spacing.
|
||||
subspan!("why I hide? hi!"); //~ ERROR found 'hi's
|
||||
subspan!("hey, hi, hidy, hidy, hi hi"); //~ ERROR found 'hi's
|
||||
subspan!("this is a hi, and this is another hi"); //~ ERROR found 'hi's
|
||||
subspan!("how are you this evening"); //~ ERROR found 'hi's
|
||||
subspan!("this is highly eradic"); //~ ERROR found 'hi's
|
||||
|
||||
fn main() { }
|
98
src/test/ui-fulldeps/subspan.stderr
Normal file
98
src/test/ui-fulldeps/subspan.stderr
Normal file
@ -0,0 +1,98 @@
|
||||
error: found 'hi's
|
||||
--> $DIR/subspan.rs:22:1
|
||||
|
|
||||
LL | subspan!("hi"); //~ ERROR found 'hi's
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: here
|
||||
--> $DIR/subspan.rs:22:11
|
||||
|
|
||||
LL | subspan!("hi"); //~ ERROR found 'hi's
|
||||
| ^^
|
||||
|
||||
error: found 'hi's
|
||||
--> $DIR/subspan.rs:25:1
|
||||
|
|
||||
LL | subspan!("hihi"); //~ ERROR found 'hi's
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: here
|
||||
--> $DIR/subspan.rs:25:11
|
||||
|
|
||||
LL | subspan!("hihi"); //~ ERROR found 'hi's
|
||||
| ^^^^
|
||||
|
||||
error: found 'hi's
|
||||
--> $DIR/subspan.rs:28:1
|
||||
|
|
||||
LL | subspan!("hihihi"); //~ ERROR found 'hi's
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: here
|
||||
--> $DIR/subspan.rs:28:11
|
||||
|
|
||||
LL | subspan!("hihihi"); //~ ERROR found 'hi's
|
||||
| ^^^^^^
|
||||
|
||||
error: found 'hi's
|
||||
--> $DIR/subspan.rs:31:1
|
||||
|
|
||||
LL | subspan!("why I hide? hi!"); //~ ERROR found 'hi's
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: here
|
||||
--> $DIR/subspan.rs:31:17
|
||||
|
|
||||
LL | subspan!("why I hide? hi!"); //~ ERROR found 'hi's
|
||||
| ^^ ^^
|
||||
|
||||
error: found 'hi's
|
||||
--> $DIR/subspan.rs:32:1
|
||||
|
|
||||
LL | subspan!("hey, hi, hidy, hidy, hi hi"); //~ ERROR found 'hi's
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: here
|
||||
--> $DIR/subspan.rs:32:16
|
||||
|
|
||||
LL | subspan!("hey, hi, hidy, hidy, hi hi"); //~ ERROR found 'hi's
|
||||
| ^^ ^^ ^^ ^^ ^^
|
||||
|
||||
error: found 'hi's
|
||||
--> $DIR/subspan.rs:33:1
|
||||
|
|
||||
LL | subspan!("this is a hi, and this is another hi"); //~ ERROR found 'hi's
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: here
|
||||
--> $DIR/subspan.rs:33:12
|
||||
|
|
||||
LL | subspan!("this is a hi, and this is another hi"); //~ ERROR found 'hi's
|
||||
| ^^ ^^ ^^ ^^
|
||||
|
||||
error: found 'hi's
|
||||
--> $DIR/subspan.rs:34:1
|
||||
|
|
||||
LL | subspan!("how are you this evening"); //~ ERROR found 'hi's
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: here
|
||||
--> $DIR/subspan.rs:34:24
|
||||
|
|
||||
LL | subspan!("how are you this evening"); //~ ERROR found 'hi's
|
||||
| ^^
|
||||
|
||||
error: found 'hi's
|
||||
--> $DIR/subspan.rs:35:1
|
||||
|
|
||||
LL | subspan!("this is highly eradic"); //~ ERROR found 'hi's
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: here
|
||||
--> $DIR/subspan.rs:35:12
|
||||
|
|
||||
LL | subspan!("this is highly eradic"); //~ ERROR found 'hi's
|
||||
| ^^ ^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user