1
Fork 0

Introduce InnerSpan abstraction

This should be used when trying to get at subsets of a larger span,
especially when the larger span is not available in the code attempting
to work with those subsets (especially common in the fmt_macros crate).

This is usually a good replacement for (BytePos, BytePos) and (usize,
usize) tuples.

This commit also removes from_inner_byte_pos, since it took usize
arguments, which is error prone.
This commit is contained in:
Mark Rousskov 2019-06-04 09:03:43 -06:00
parent a859440092
commit b1c357e0c3
6 changed files with 82 additions and 75 deletions

View file

@ -24,7 +24,16 @@ use std::str;
use std::string; use std::string;
use std::iter; use std::iter;
use syntax_pos::Symbol; use syntax_pos::{InnerSpan, Symbol};
#[derive(Copy, Clone)]
struct InnerOffset(usize);
impl InnerOffset {
fn to(self, end: InnerOffset) -> InnerSpan {
InnerSpan::new(self.0, end.0)
}
}
/// A piece is a portion of the format string which represents the next part /// A piece is a portion of the format string which represents the next part
/// to emit. These are emitted as a stream by the `Parser` class. /// to emit. These are emitted as a stream by the `Parser` class.
@ -136,9 +145,8 @@ pub struct ParseError {
pub description: string::String, pub description: string::String,
pub note: Option<string::String>, pub note: Option<string::String>,
pub label: string::String, pub label: string::String,
pub start: SpanIndex, pub span: InnerSpan,
pub end: SpanIndex, pub secondary_label: Option<(string::String, InnerSpan)>,
pub secondary_label: Option<(string::String, SpanIndex, SpanIndex)>,
} }
/// The parser structure for interpreting the input format string. This is /// The parser structure for interpreting the input format string. This is
@ -157,24 +165,15 @@ pub struct Parser<'a> {
/// `Some(raw count)` when the string is "raw", used to position spans correctly /// `Some(raw count)` when the string is "raw", used to position spans correctly
style: Option<usize>, style: Option<usize>,
/// Start and end byte offset of every successfully parsed argument /// Start and end byte offset of every successfully parsed argument
pub arg_places: Vec<(SpanIndex, SpanIndex)>, pub arg_places: Vec<InnerSpan>,
/// Characters that need to be shifted /// Characters that need to be shifted
skips: Vec<usize>, skips: Vec<usize>,
/// Span offset of the last opening brace seen, used for error reporting /// Span of the last opening brace seen, used for error reporting
last_opening_brace_pos: Option<SpanIndex>, last_opening_brace: Option<InnerSpan>,
/// Wether the source string is comes from `println!` as opposed to `format!` or `print!` /// Wether the source string is comes from `println!` as opposed to `format!` or `print!`
append_newline: bool, append_newline: bool,
} }
#[derive(Clone, Copy, Debug)]
pub struct SpanIndex(pub usize);
impl SpanIndex {
pub fn unwrap(self) -> usize {
self.0
}
}
impl<'a> Iterator for Parser<'a> { impl<'a> Iterator for Parser<'a> {
type Item = Piece<'a>; type Item = Piece<'a>;
@ -182,19 +181,20 @@ impl<'a> Iterator for Parser<'a> {
if let Some(&(pos, c)) = self.cur.peek() { if let Some(&(pos, c)) = self.cur.peek() {
match c { match c {
'{' => { '{' => {
let curr_last_brace = self.last_opening_brace_pos; let curr_last_brace = self.last_opening_brace;
self.last_opening_brace_pos = Some(self.to_span_index(pos)); let byte_pos = self.to_span_index(pos);
self.last_opening_brace = Some(byte_pos.to(byte_pos));
self.cur.next(); self.cur.next();
if self.consume('{') { if self.consume('{') {
self.last_opening_brace_pos = curr_last_brace; self.last_opening_brace = curr_last_brace;
Some(String(self.string(pos + 1))) Some(String(self.string(pos + 1)))
} else { } else {
let arg = self.argument(); let arg = self.argument();
if let Some(arg_pos) = self.must_consume('}').map(|end| { if let Some(end) = self.must_consume('}') {
(self.to_span_index(pos), self.to_span_index(end + 1)) let start = self.to_span_index(pos);
}) { let end = self.to_span_index(end + 1);
self.arg_places.push(arg_pos); self.arg_places.push(start.to(end));
} }
Some(NextArgument(arg)) Some(NextArgument(arg))
} }
@ -209,8 +209,7 @@ impl<'a> Iterator for Parser<'a> {
"unmatched `}` found", "unmatched `}` found",
"unmatched `}`", "unmatched `}`",
"if you intended to print `}`, you can escape it using `}}`", "if you intended to print `}`, you can escape it using `}}`",
err_pos, err_pos.to(err_pos),
err_pos,
); );
None None
} }
@ -242,7 +241,7 @@ impl<'a> Parser<'a> {
style, style,
arg_places: vec![], arg_places: vec![],
skips, skips,
last_opening_brace_pos: None, last_opening_brace: None,
append_newline, append_newline,
} }
} }
@ -254,15 +253,13 @@ impl<'a> Parser<'a> {
&mut self, &mut self,
description: S1, description: S1,
label: S2, label: S2,
start: SpanIndex, span: InnerSpan,
end: SpanIndex,
) { ) {
self.errors.push(ParseError { self.errors.push(ParseError {
description: description.into(), description: description.into(),
note: None, note: None,
label: label.into(), label: label.into(),
start, span,
end,
secondary_label: None, secondary_label: None,
}); });
} }
@ -275,15 +272,13 @@ impl<'a> Parser<'a> {
description: S1, description: S1,
label: S2, label: S2,
note: S3, note: S3,
start: SpanIndex, span: InnerSpan,
end: SpanIndex,
) { ) {
self.errors.push(ParseError { self.errors.push(ParseError {
description: description.into(), description: description.into(),
note: Some(note.into()), note: Some(note.into()),
label: label.into(), label: label.into(),
start, span,
end,
secondary_label: None, secondary_label: None,
}); });
} }
@ -304,7 +299,7 @@ impl<'a> Parser<'a> {
} }
} }
fn to_span_index(&self, pos: usize) -> SpanIndex { fn to_span_index(&self, pos: usize) -> InnerOffset {
let mut pos = pos; let mut pos = pos;
let raw = self.style.map(|raw| raw + 1).unwrap_or(0); let raw = self.style.map(|raw| raw + 1).unwrap_or(0);
for skip in &self.skips { for skip in &self.skips {
@ -316,7 +311,7 @@ impl<'a> Parser<'a> {
break; break;
} }
} }
SpanIndex(raw + pos + 1) InnerOffset(raw + pos + 1)
} }
/// Forces consumption of the specified character. If the character is not /// Forces consumption of the specified character. If the character is not
@ -334,8 +329,8 @@ impl<'a> Parser<'a> {
let label = "expected `}`".to_owned(); let label = "expected `}`".to_owned();
let (note, secondary_label) = if c == '}' { let (note, secondary_label) = if c == '}' {
(Some("if you intended to print `{`, you can escape it using `{{`".to_owned()), (Some("if you intended to print `{`, you can escape it using `{{`".to_owned()),
self.last_opening_brace_pos.map(|pos| { self.last_opening_brace.map(|sp| {
("because of this opening brace".to_owned(), pos, pos) ("because of this opening brace".to_owned(), sp)
})) }))
} else { } else {
(None, None) (None, None)
@ -344,8 +339,7 @@ impl<'a> Parser<'a> {
description, description,
note, note,
label, label,
start: pos, span: pos.to(pos),
end: pos,
secondary_label, secondary_label,
}); });
None None
@ -359,8 +353,8 @@ impl<'a> Parser<'a> {
let label = format!("expected `{:?}`", c); let label = format!("expected `{:?}`", c);
let (note, secondary_label) = if c == '}' { let (note, secondary_label) = if c == '}' {
(Some("if you intended to print `{`, you can escape it using `{{`".to_owned()), (Some("if you intended to print `{`, you can escape it using `{{`".to_owned()),
self.last_opening_brace_pos.map(|pos| { self.last_opening_brace.map(|sp| {
("because of this opening brace".to_owned(), pos, pos) ("because of this opening brace".to_owned(), sp)
})) }))
} else { } else {
(None, None) (None, None)
@ -369,12 +363,11 @@ impl<'a> Parser<'a> {
description, description,
note, note,
label, label,
start: pos, span: pos.to(pos),
end: pos,
secondary_label, secondary_label,
}); });
} else { } else {
self.err(description, format!("expected `{:?}`", c), pos, pos); self.err(description, format!("expected `{:?}`", c), pos.to(pos));
} }
None None
} }
@ -446,8 +439,10 @@ impl<'a> Parser<'a> {
self.err_with_note(format!("invalid argument name `{}`", invalid_name), self.err_with_note(format!("invalid argument name `{}`", invalid_name),
"invalid argument name", "invalid argument name",
"argument names cannot start with an underscore", "argument names cannot start with an underscore",
self.to_span_index(pos), self.to_span_index(pos).to(
self.to_span_index(pos + invalid_name.len())); self.to_span_index(pos + invalid_name.len())
),
);
Some(ArgumentNamed(Symbol::intern(invalid_name))) Some(ArgumentNamed(Symbol::intern(invalid_name)))
}, },

View file

@ -2,7 +2,7 @@ use errors::Applicability;
use syntax::parse::lexer::{StringReader as Lexer}; use syntax::parse::lexer::{StringReader as Lexer};
use syntax::parse::{ParseSess, token}; use syntax::parse::{ParseSess, token};
use syntax::source_map::FilePathMapping; use syntax::source_map::FilePathMapping;
use syntax_pos::FileName; use syntax_pos::{InnerSpan, FileName};
use crate::clean; use crate::clean;
use crate::core::DocContext; use crate::core::DocContext;
@ -63,7 +63,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
} }
if code_block.syntax.is_none() && code_block.is_fenced { if code_block.syntax.is_none() && code_block.is_fenced {
let sp = sp.from_inner_byte_pos(0, 3); let sp = sp.from_inner(InnerSpan::new(0, 3));
diag.span_suggestion( diag.span_suggestion(
sp, sp,
"mark blocks that do not contain Rust code as text", "mark blocks that do not contain Rust code as text",

View file

@ -6,7 +6,7 @@ use rustc::lint as lint;
use rustc::middle::privacy::AccessLevels; use rustc::middle::privacy::AccessLevels;
use rustc::util::nodemap::DefIdSet; use rustc::util::nodemap::DefIdSet;
use std::mem; use std::mem;
use syntax_pos::{DUMMY_SP, Span}; use syntax_pos::{DUMMY_SP, InnerSpan, Span};
use std::ops::Range; use std::ops::Range;
use crate::clean::{self, GetDefId, Item}; use crate::clean::{self, GetDefId, Item};
@ -440,10 +440,10 @@ crate fn source_span_for_markdown_range(
} }
} }
let sp = span_of_attrs(attrs).from_inner_byte_pos( let sp = span_of_attrs(attrs).from_inner(InnerSpan::new(
md_range.start + start_bytes, md_range.start + start_bytes,
md_range.end + start_bytes + end_bytes, md_range.end + start_bytes + end_bytes,
); ));
Some(sp) Some(sp)
} }

View file

@ -900,15 +900,15 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>,
if !parser.errors.is_empty() { if !parser.errors.is_empty() {
let err = parser.errors.remove(0); let err = parser.errors.remove(0);
let sp = fmt.span.from_inner_byte_pos(err.start.unwrap(), err.end.unwrap()); let sp = fmt.span.from_inner(err.span);
let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}", let mut e = ecx.struct_span_err(sp, &format!("invalid format string: {}",
err.description)); err.description));
e.span_label(sp, err.label + " in format string"); e.span_label(sp, err.label + " in format string");
if let Some(note) = err.note { if let Some(note) = err.note {
e.note(&note); e.note(&note);
} }
if let Some((label, start, end)) = err.secondary_label { if let Some((label, span)) = err.secondary_label {
let sp = fmt.span.from_inner_byte_pos(start.unwrap(), end.unwrap()); let sp = fmt.span.from_inner(span);
e.span_label(sp, label); e.span_label(sp, label);
} }
e.emit(); e.emit();
@ -916,9 +916,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>,
} }
let arg_spans = parser.arg_places.iter() let arg_spans = parser.arg_places.iter()
.map(|&(parse::SpanIndex(start), parse::SpanIndex(end))| { .map(|span| fmt.span.from_inner(*span))
fmt.span.from_inner_byte_pos(start, end)
})
.collect(); .collect();
let mut cx = Context { let mut cx = Context {
@ -1065,8 +1063,8 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt<'_>,
show_doc_note = true; show_doc_note = true;
} }
if let Some((start, end)) = pos { if let Some(inner_sp) = pos {
let sp = fmt_sp.from_inner_byte_pos(start, end); let sp = fmt_sp.from_inner(inner_sp);
suggestions.push((sp, trn)); suggestions.push((sp, trn));
} else { } else {
diag.help(&format!("`{}` should be written as `{}`", sub, trn)); diag.help(&format!("`{}` should be written as `{}`", sub, trn));

View file

@ -1,5 +1,6 @@
pub mod printf { pub mod printf {
use super::strcursor::StrCursor as Cur; use super::strcursor::StrCursor as Cur;
use syntax_pos::InnerSpan;
/// Represents a single `printf`-style substitution. /// Represents a single `printf`-style substitution.
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
@ -18,7 +19,7 @@ pub mod printf {
} }
} }
pub fn position(&self) -> Option<(usize, usize)> { pub fn position(&self) -> Option<InnerSpan> {
match *self { match *self {
Substitution::Format(ref fmt) => Some(fmt.position), Substitution::Format(ref fmt) => Some(fmt.position),
_ => None, _ => None,
@ -28,7 +29,7 @@ pub mod printf {
pub fn set_position(&mut self, start: usize, end: usize) { pub fn set_position(&mut self, start: usize, end: usize) {
match self { match self {
Substitution::Format(ref mut fmt) => { Substitution::Format(ref mut fmt) => {
fmt.position = (start, end); fmt.position = InnerSpan::new(start, end);
} }
_ => {} _ => {}
} }
@ -65,7 +66,7 @@ pub mod printf {
/// Type of parameter being converted. /// Type of parameter being converted.
pub type_: &'a str, pub type_: &'a str,
/// Byte offset for the start and end of this formatting directive. /// Byte offset for the start and end of this formatting directive.
pub position: (usize, usize), pub position: InnerSpan,
} }
impl Format<'_> { impl Format<'_> {
@ -282,9 +283,9 @@ pub mod printf {
let (mut sub, tail) = parse_next_substitution(self.s)?; let (mut sub, tail) = parse_next_substitution(self.s)?;
self.s = tail; self.s = tail;
match sub { match sub {
Substitution::Format(_) => if let Some((start, end)) = sub.position() { Substitution::Format(_) => if let Some(inner_span) = sub.position() {
sub.set_position(start + self.pos, end + self.pos); sub.set_position(inner_span.start + self.pos, inner_span.end + self.pos);
self.pos += end; self.pos += inner_span.end;
} }
Substitution::Escape => self.pos += 2, Substitution::Escape => self.pos += 2,
} }
@ -373,7 +374,7 @@ pub mod printf {
precision: None, precision: None,
length: None, length: None,
type_: at.slice_between(next).unwrap(), type_: at.slice_between(next).unwrap(),
position: (start.at, next.at), position: InnerSpan::new(start.at, next.at),
}), }),
next.slice_after() next.slice_after()
)); ));
@ -560,7 +561,7 @@ pub mod printf {
drop(next); drop(next);
end = at; end = at;
let position = (start.at, end.at); let position = InnerSpan::new(start.at, end.at);
let f = Format { let f = Format {
span: start.slice_between(end).unwrap(), span: start.slice_between(end).unwrap(),
@ -650,7 +651,7 @@ pub mod printf {
precision: $prec, precision: $prec,
length: $len, length: $len,
type_: $type_, type_: $type_,
position: $pos, position: syntax_pos::InnerSpan::new($pos.0, $pos.1),
}), }),
"!" "!"
)) ))
@ -761,6 +762,7 @@ pub mod printf {
pub mod shell { pub mod shell {
use super::strcursor::StrCursor as Cur; use super::strcursor::StrCursor as Cur;
use syntax_pos::InnerSpan;
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
pub enum Substitution<'a> { pub enum Substitution<'a> {
@ -778,11 +780,11 @@ pub mod shell {
} }
} }
pub fn position(&self) -> Option<(usize, usize)> { pub fn position(&self) -> Option<InnerSpan> {
match self { match self {
Substitution::Ordinal(_, pos) | Substitution::Ordinal(_, pos) |
Substitution::Name(_, pos) | Substitution::Name(_, pos) |
Substitution::Escape(pos) => Some(*pos), Substitution::Escape(pos) => Some(InnerSpan::new(pos.0, pos.1)),
} }
} }
@ -823,7 +825,7 @@ pub mod shell {
match parse_next_substitution(self.s) { match parse_next_substitution(self.s) {
Some((mut sub, tail)) => { Some((mut sub, tail)) => {
self.s = tail; self.s = tail;
if let Some((start, end)) = sub.position() { if let Some(InnerSpan { start, end }) = sub.position() {
sub.set_position(start + self.pos, end + self.pos); sub.set_position(start + self.pos, end + self.pos);
self.pos += end; self.pos += end;
} }

View file

@ -504,10 +504,10 @@ impl Span {
) )
} }
pub fn from_inner_byte_pos(self, start: usize, end: usize) -> Span { pub fn from_inner(self, inner: InnerSpan) -> Span {
let span = self.data(); let span = self.data();
Span::new(span.lo + BytePos::from_usize(start), Span::new(span.lo + BytePos::from_usize(inner.start),
span.lo + BytePos::from_usize(end), span.lo + BytePos::from_usize(inner.end),
span.ctxt) span.ctxt)
} }
@ -1395,6 +1395,18 @@ pub struct MalformedSourceMapPositions {
pub end_pos: BytePos pub end_pos: BytePos
} }
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct InnerSpan {
pub start: usize,
pub end: usize,
}
impl InnerSpan {
pub fn new(start: usize, end: usize) -> InnerSpan {
InnerSpan { start, end }
}
}
// Given a slice of line start positions and a position, returns the index of // Given a slice of line start positions and a position, returns the index of
// the line the position is on. Returns -1 if the position is located before // the line the position is on. Returns -1 if the position is located before
// the first line. // the first line.