mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
Make rustc_parse_format compile on stable
This allows it to be used by lightweight formatting systems and may allow it to be used by rust-analyzer.
This commit is contained in:
parent
683c582c1e
commit
d33140d2dc
@ -4171,7 +4171,6 @@ name = "rustc_parse_format"
|
|||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustc_lexer",
|
"rustc_lexer",
|
||||||
"rustc_span",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -626,7 +626,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
|||||||
|
|
||||||
if !parser.errors.is_empty() {
|
if !parser.errors.is_empty() {
|
||||||
let err = parser.errors.remove(0);
|
let err = parser.errors.remove(0);
|
||||||
let err_sp = template_span.from_inner(err.span);
|
let err_sp = template_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
|
||||||
let msg = &format!("invalid asm template string: {}", err.description);
|
let msg = &format!("invalid asm template string: {}", err.description);
|
||||||
let mut e = ecx.struct_span_err(err_sp, msg);
|
let mut e = ecx.struct_span_err(err_sp, msg);
|
||||||
e.span_label(err_sp, err.label + " in asm template string");
|
e.span_label(err_sp, err.label + " in asm template string");
|
||||||
@ -634,7 +634,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
|||||||
e.note(¬e);
|
e.note(¬e);
|
||||||
}
|
}
|
||||||
if let Some((label, span)) = err.secondary_label {
|
if let Some((label, span)) = err.secondary_label {
|
||||||
let err_sp = template_span.from_inner(span);
|
let err_sp = template_span.from_inner(InnerSpan::new(span.start, span.end));
|
||||||
e.span_label(err_sp, label);
|
e.span_label(err_sp, label);
|
||||||
}
|
}
|
||||||
e.emit();
|
e.emit();
|
||||||
@ -643,7 +643,10 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
|||||||
|
|
||||||
curarg = parser.curarg;
|
curarg = parser.curarg;
|
||||||
|
|
||||||
let mut arg_spans = parser.arg_places.iter().map(|span| template_span.from_inner(*span));
|
let mut arg_spans = parser
|
||||||
|
.arg_places
|
||||||
|
.iter()
|
||||||
|
.map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end)));
|
||||||
for piece in unverified_pieces {
|
for piece in unverified_pieces {
|
||||||
match piece {
|
match piece {
|
||||||
parse::Piece::String(s) => {
|
parse::Piece::String(s) => {
|
||||||
@ -699,14 +702,21 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
|||||||
Some(idx)
|
Some(idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parse::ArgumentNamed(name, span) => match args.named_args.get(&name) {
|
parse::ArgumentNamed(name, span) => {
|
||||||
Some(&idx) => Some(idx),
|
match args.named_args.get(&Symbol::intern(name)) {
|
||||||
None => {
|
Some(&idx) => Some(idx),
|
||||||
let msg = format!("there is no argument named `{}`", name);
|
None => {
|
||||||
ecx.struct_span_err(template_span.from_inner(span), &msg).emit();
|
let msg = format!("there is no argument named `{}`", name);
|
||||||
None
|
ecx.struct_span_err(
|
||||||
|
template_span
|
||||||
|
.from_inner(InnerSpan::new(span.start, span.end)),
|
||||||
|
&msg,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut chars = arg.format.ty.chars();
|
let mut chars = arg.format.ty.chars();
|
||||||
@ -715,7 +725,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
|||||||
let span = arg
|
let span = arg
|
||||||
.format
|
.format
|
||||||
.ty_span
|
.ty_span
|
||||||
.map(|sp| template_sp.from_inner(sp))
|
.map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end)))
|
||||||
.unwrap_or(template_sp);
|
.unwrap_or(template_sp);
|
||||||
ecx.struct_span_err(
|
ecx.struct_span_err(
|
||||||
span,
|
span,
|
||||||
@ -741,7 +751,12 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
|
|||||||
let template_num_lines = 1 + template_str.matches('\n').count();
|
let template_num_lines = 1 + template_str.matches('\n').count();
|
||||||
line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines));
|
line_spans.extend(std::iter::repeat(template_sp).take(template_num_lines));
|
||||||
} else {
|
} else {
|
||||||
line_spans.extend(parser.line_spans.iter().map(|span| template_span.from_inner(*span)));
|
line_spans.extend(
|
||||||
|
parser
|
||||||
|
.line_spans
|
||||||
|
.iter()
|
||||||
|
.map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end))),
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
|
fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
|
||||||
// NOTE: the `unwrap_or` branch is needed in case of invalid format
|
// NOTE: the `unwrap_or` branch is needed in case of invalid format
|
||||||
// arguments, e.g., `format_args!("{foo}")`.
|
// arguments, e.g., `format_args!("{foo}")`.
|
||||||
let lookup = |s: Symbol| *self.names.get(&s).unwrap_or(&0);
|
let lookup = |s: &str| *self.names.get(&Symbol::intern(s)).unwrap_or(&0);
|
||||||
|
|
||||||
match *p {
|
match *p {
|
||||||
parse::String(_) => {}
|
parse::String(_) => {}
|
||||||
@ -276,7 +276,9 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
// it's written second, so it should come after width/precision.
|
// it's written second, so it should come after width/precision.
|
||||||
let pos = match arg.position {
|
let pos = match arg.position {
|
||||||
parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
|
parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
|
||||||
parse::ArgumentNamed(s, span) => Named(s, span),
|
parse::ArgumentNamed(s, span) => {
|
||||||
|
Named(Symbol::intern(s), InnerSpan::new(span.start, span.end))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty = Placeholder(match arg.format.ty {
|
let ty = Placeholder(match arg.format.ty {
|
||||||
@ -291,7 +293,10 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
"X" => "UpperHex",
|
"X" => "UpperHex",
|
||||||
_ => {
|
_ => {
|
||||||
let fmtsp = self.fmtsp;
|
let fmtsp = self.fmtsp;
|
||||||
let sp = arg.format.ty_span.map(|sp| fmtsp.from_inner(sp));
|
let sp = arg
|
||||||
|
.format
|
||||||
|
.ty_span
|
||||||
|
.map(|sp| fmtsp.from_inner(InnerSpan::new(sp.start, sp.end)));
|
||||||
let mut err = self.ecx.struct_span_err(
|
let mut err = self.ecx.struct_span_err(
|
||||||
sp.unwrap_or(fmtsp),
|
sp.unwrap_or(fmtsp),
|
||||||
&format!("unknown format trait `{}`", arg.format.ty),
|
&format!("unknown format trait `{}`", arg.format.ty),
|
||||||
@ -340,14 +345,17 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_count(&mut self, c: parse::Count) {
|
fn verify_count(&mut self, c: parse::Count<'_>) {
|
||||||
match c {
|
match c {
|
||||||
parse::CountImplied | parse::CountIs(..) => {}
|
parse::CountImplied | parse::CountIs(..) => {}
|
||||||
parse::CountIsParam(i) => {
|
parse::CountIsParam(i) => {
|
||||||
self.verify_arg_type(Exact(i), Count);
|
self.verify_arg_type(Exact(i), Count);
|
||||||
}
|
}
|
||||||
parse::CountIsName(s, span) => {
|
parse::CountIsName(s, span) => {
|
||||||
self.verify_arg_type(Named(s, span), Count);
|
self.verify_arg_type(
|
||||||
|
Named(Symbol::intern(s), InnerSpan::new(span.start, span.end)),
|
||||||
|
Count,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -425,7 +433,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
|
|
||||||
for fmt in &self.arg_with_formatting {
|
for fmt in &self.arg_with_formatting {
|
||||||
if let Some(span) = fmt.precision_span {
|
if let Some(span) = fmt.precision_span {
|
||||||
let span = self.fmtsp.from_inner(span);
|
let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
|
||||||
match fmt.precision {
|
match fmt.precision {
|
||||||
parse::CountIsParam(pos) if pos > self.num_args() => {
|
parse::CountIsParam(pos) if pos > self.num_args() => {
|
||||||
e.span_label(
|
e.span_label(
|
||||||
@ -471,7 +479,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(span) = fmt.width_span {
|
if let Some(span) = fmt.width_span {
|
||||||
let span = self.fmtsp.from_inner(span);
|
let span = self.fmtsp.from_inner(InnerSpan::new(span.start, span.end));
|
||||||
match fmt.width {
|
match fmt.width {
|
||||||
parse::CountIsParam(pos) if pos > self.num_args() => {
|
parse::CountIsParam(pos) if pos > self.num_args() => {
|
||||||
e.span_label(
|
e.span_label(
|
||||||
@ -610,7 +618,7 @@ impl<'a, 'b> Context<'a, 'b> {
|
|||||||
ecx.std_path(&[sym::fmt, sym::rt, sym::v1, s])
|
ecx.std_path(&[sym::fmt, sym::rt, sym::v1, s])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_count(&self, c: parse::Count) -> P<ast::Expr> {
|
fn build_count(&self, c: parse::Count<'_>) -> P<ast::Expr> {
|
||||||
let sp = self.macsp;
|
let sp = self.macsp;
|
||||||
let count = |c, arg| {
|
let count = |c, arg| {
|
||||||
let mut path = Context::rtpath(self.ecx, sym::Count);
|
let mut path = Context::rtpath(self.ecx, sym::Count);
|
||||||
@ -1033,7 +1041,7 @@ pub fn expand_preparsed_format_args(
|
|||||||
if !parser.errors.is_empty() {
|
if !parser.errors.is_empty() {
|
||||||
let err = parser.errors.remove(0);
|
let err = parser.errors.remove(0);
|
||||||
let sp = if efmt_kind_is_lit {
|
let sp = if efmt_kind_is_lit {
|
||||||
fmt_span.from_inner(err.span)
|
fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end))
|
||||||
} else {
|
} else {
|
||||||
// The format string could be another macro invocation, e.g.:
|
// The format string could be another macro invocation, e.g.:
|
||||||
// format!(concat!("abc", "{}"), 4);
|
// format!(concat!("abc", "{}"), 4);
|
||||||
@ -1052,14 +1060,18 @@ pub fn expand_preparsed_format_args(
|
|||||||
}
|
}
|
||||||
if let Some((label, span)) = err.secondary_label {
|
if let Some((label, span)) = err.secondary_label {
|
||||||
if efmt_kind_is_lit {
|
if efmt_kind_is_lit {
|
||||||
e.span_label(fmt_span.from_inner(span), label);
|
e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e.emit();
|
e.emit();
|
||||||
return DummyResult::raw_expr(sp, true);
|
return DummyResult::raw_expr(sp, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
let arg_spans = parser.arg_places.iter().map(|span| fmt_span.from_inner(*span)).collect();
|
let arg_spans = parser
|
||||||
|
.arg_places
|
||||||
|
.iter()
|
||||||
|
.map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
let named_pos: FxHashSet<usize> = names.values().cloned().collect();
|
let named_pos: FxHashSet<usize> = names.values().cloned().collect();
|
||||||
|
|
||||||
|
@ -254,7 +254,10 @@ fn check_panic_str<'tcx>(
|
|||||||
if n_arguments > 0 && fmt_parser.errors.is_empty() {
|
if n_arguments > 0 && fmt_parser.errors.is_empty() {
|
||||||
let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
|
let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
|
||||||
[] => vec![fmt_span],
|
[] => vec![fmt_span],
|
||||||
v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(),
|
v => v
|
||||||
|
.iter()
|
||||||
|
.map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
|
||||||
|
.collect(),
|
||||||
};
|
};
|
||||||
cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
|
cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
|
||||||
let mut l = lint.build(match n_arguments {
|
let mut l = lint.build(match n_arguments {
|
||||||
|
@ -4,5 +4,4 @@ version = "0.0.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rustc_span = { path = "../rustc_span" }
|
|
||||||
rustc_lexer = { path = "../rustc_lexer" }
|
rustc_lexer = { path = "../rustc_lexer" }
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
html_playground_url = "https://play.rust-lang.org/",
|
html_playground_url = "https://play.rust-lang.org/",
|
||||||
test(attr(deny(warnings)))
|
test(attr(deny(warnings)))
|
||||||
)]
|
)]
|
||||||
#![feature(nll)]
|
// We want to be able to build this crate with a stable compiler, so no
|
||||||
#![feature(bool_to_option)]
|
// `#![feature]` attributes should be added.
|
||||||
|
|
||||||
pub use Alignment::*;
|
pub use Alignment::*;
|
||||||
pub use Count::*;
|
pub use Count::*;
|
||||||
@ -22,7 +22,19 @@ use std::iter;
|
|||||||
use std::str;
|
use std::str;
|
||||||
use std::string;
|
use std::string;
|
||||||
|
|
||||||
use rustc_span::{InnerSpan, Symbol};
|
// Note: copied from rustc_span
|
||||||
|
/// Range inside of a `Span` used for diagnostics when we only have access to relative positions.
|
||||||
|
#[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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The type of format string that we are parsing.
|
/// The type of format string that we are parsing.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
@ -57,7 +69,7 @@ pub enum Piece<'a> {
|
|||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub struct Argument<'a> {
|
pub struct Argument<'a> {
|
||||||
/// Where to find this argument
|
/// Where to find this argument
|
||||||
pub position: Position,
|
pub position: Position<'a>,
|
||||||
/// How to format the argument
|
/// How to format the argument
|
||||||
pub format: FormatSpec<'a>,
|
pub format: FormatSpec<'a>,
|
||||||
}
|
}
|
||||||
@ -72,11 +84,11 @@ pub struct FormatSpec<'a> {
|
|||||||
/// Packed version of various flags provided.
|
/// Packed version of various flags provided.
|
||||||
pub flags: u32,
|
pub flags: u32,
|
||||||
/// The integer precision to use.
|
/// The integer precision to use.
|
||||||
pub precision: Count,
|
pub precision: Count<'a>,
|
||||||
/// The span of the precision formatting flag (for diagnostics).
|
/// The span of the precision formatting flag (for diagnostics).
|
||||||
pub precision_span: Option<InnerSpan>,
|
pub precision_span: Option<InnerSpan>,
|
||||||
/// The string width requested for the resulting format.
|
/// The string width requested for the resulting format.
|
||||||
pub width: Count,
|
pub width: Count<'a>,
|
||||||
/// The span of the width formatting flag (for diagnostics).
|
/// The span of the width formatting flag (for diagnostics).
|
||||||
pub width_span: Option<InnerSpan>,
|
pub width_span: Option<InnerSpan>,
|
||||||
/// The descriptor string representing the name of the format desired for
|
/// The descriptor string representing the name of the format desired for
|
||||||
@ -89,16 +101,16 @@ pub struct FormatSpec<'a> {
|
|||||||
|
|
||||||
/// Enum describing where an argument for a format can be located.
|
/// Enum describing where an argument for a format can be located.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub enum Position {
|
pub enum Position<'a> {
|
||||||
/// The argument is implied to be located at an index
|
/// The argument is implied to be located at an index
|
||||||
ArgumentImplicitlyIs(usize),
|
ArgumentImplicitlyIs(usize),
|
||||||
/// The argument is located at a specific index given in the format
|
/// The argument is located at a specific index given in the format
|
||||||
ArgumentIs(usize),
|
ArgumentIs(usize),
|
||||||
/// The argument has a name.
|
/// The argument has a name.
|
||||||
ArgumentNamed(Symbol, InnerSpan),
|
ArgumentNamed(&'a str, InnerSpan),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Position {
|
impl Position<'_> {
|
||||||
pub fn index(&self) -> Option<usize> {
|
pub fn index(&self) -> Option<usize> {
|
||||||
match self {
|
match self {
|
||||||
ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i),
|
ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i),
|
||||||
@ -143,11 +155,11 @@ pub enum Flag {
|
|||||||
/// A count is used for the precision and width parameters of an integer, and
|
/// A count is used for the precision and width parameters of an integer, and
|
||||||
/// can reference either an argument or a literal integer.
|
/// can reference either an argument or a literal integer.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub enum Count {
|
pub enum Count<'a> {
|
||||||
/// The count is specified explicitly.
|
/// The count is specified explicitly.
|
||||||
CountIs(usize),
|
CountIs(usize),
|
||||||
/// The count is specified by the argument with the given name.
|
/// The count is specified by the argument with the given name.
|
||||||
CountIsName(Symbol, InnerSpan),
|
CountIsName(&'a str, InnerSpan),
|
||||||
/// The count is specified by the argument at the given index.
|
/// The count is specified by the argument at the given index.
|
||||||
CountIsParam(usize),
|
CountIsParam(usize),
|
||||||
/// The count is implied and cannot be explicitly specified.
|
/// The count is implied and cannot be explicitly specified.
|
||||||
@ -489,7 +501,7 @@ impl<'a> Parser<'a> {
|
|||||||
/// integer index of an argument, a named argument, or a blank string.
|
/// integer index of an argument, a named argument, or a blank string.
|
||||||
/// Returns `Some(parsed_position)` if the position is not implicitly
|
/// Returns `Some(parsed_position)` if the position is not implicitly
|
||||||
/// consuming a macro argument, `None` if it's the case.
|
/// consuming a macro argument, `None` if it's the case.
|
||||||
fn position(&mut self) -> Option<Position> {
|
fn position(&mut self) -> Option<Position<'a>> {
|
||||||
if let Some(i) = self.integer() {
|
if let Some(i) = self.integer() {
|
||||||
Some(ArgumentIs(i))
|
Some(ArgumentIs(i))
|
||||||
} else {
|
} else {
|
||||||
@ -498,7 +510,7 @@ impl<'a> Parser<'a> {
|
|||||||
let word = self.word();
|
let word = self.word();
|
||||||
let end = start + word.len();
|
let end = start + word.len();
|
||||||
let span = self.to_span_index(start).to(self.to_span_index(end));
|
let span = self.to_span_index(start).to(self.to_span_index(end));
|
||||||
Some(ArgumentNamed(Symbol::intern(word), span))
|
Some(ArgumentNamed(word, span))
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is an `ArgumentNext`.
|
// This is an `ArgumentNext`.
|
||||||
@ -651,7 +663,7 @@ impl<'a> Parser<'a> {
|
|||||||
/// Parses a `Count` parameter at the current position. This does not check
|
/// Parses a `Count` parameter at the current position. This does not check
|
||||||
/// for 'CountIsNextParam' because that is only used in precision, not
|
/// for 'CountIsNextParam' because that is only used in precision, not
|
||||||
/// width.
|
/// width.
|
||||||
fn count(&mut self, start: usize) -> (Count, Option<InnerSpan>) {
|
fn count(&mut self, start: usize) -> (Count<'a>, Option<InnerSpan>) {
|
||||||
if let Some(i) = self.integer() {
|
if let Some(i) = self.integer() {
|
||||||
if let Some(end) = self.consume_pos('$') {
|
if let Some(end) = self.consume_pos('$') {
|
||||||
let span = self.to_span_index(start).to(self.to_span_index(end + 1));
|
let span = self.to_span_index(start).to(self.to_span_index(end + 1));
|
||||||
@ -667,7 +679,7 @@ impl<'a> Parser<'a> {
|
|||||||
(CountImplied, None)
|
(CountImplied, None)
|
||||||
} else if let Some(end) = self.consume_pos('$') {
|
} else if let Some(end) = self.consume_pos('$') {
|
||||||
let span = self.to_span_index(start + 1).to(self.to_span_index(end));
|
let span = self.to_span_index(start + 1).to(self.to_span_index(end));
|
||||||
(CountIsName(Symbol::intern(word), span), None)
|
(CountIsName(word, span), None)
|
||||||
} else {
|
} else {
|
||||||
self.cur = tmp;
|
self.cur = tmp;
|
||||||
(CountImplied, None)
|
(CountImplied, None)
|
||||||
@ -723,7 +735,7 @@ impl<'a> Parser<'a> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
found.then_some(cur)
|
if found { Some(cur) } else { None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,93 +144,91 @@ fn format_align_fill() {
|
|||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_counts() {
|
fn format_counts() {
|
||||||
rustc_span::create_default_session_globals_then(|| {
|
same(
|
||||||
same(
|
"{:10x}",
|
||||||
"{:10x}",
|
&[NextArgument(Argument {
|
||||||
&[NextArgument(Argument {
|
position: ArgumentImplicitlyIs(0),
|
||||||
position: ArgumentImplicitlyIs(0),
|
format: FormatSpec {
|
||||||
format: FormatSpec {
|
fill: None,
|
||||||
fill: None,
|
align: AlignUnknown,
|
||||||
align: AlignUnknown,
|
flags: 0,
|
||||||
flags: 0,
|
precision: CountImplied,
|
||||||
precision: CountImplied,
|
width: CountIs(10),
|
||||||
width: CountIs(10),
|
precision_span: None,
|
||||||
precision_span: None,
|
width_span: None,
|
||||||
width_span: None,
|
ty: "x",
|
||||||
ty: "x",
|
ty_span: None,
|
||||||
ty_span: None,
|
},
|
||||||
},
|
})],
|
||||||
})],
|
);
|
||||||
);
|
same(
|
||||||
same(
|
"{:10$.10x}",
|
||||||
"{:10$.10x}",
|
&[NextArgument(Argument {
|
||||||
&[NextArgument(Argument {
|
position: ArgumentImplicitlyIs(0),
|
||||||
position: ArgumentImplicitlyIs(0),
|
format: FormatSpec {
|
||||||
format: FormatSpec {
|
fill: None,
|
||||||
fill: None,
|
align: AlignUnknown,
|
||||||
align: AlignUnknown,
|
flags: 0,
|
||||||
flags: 0,
|
precision: CountIs(10),
|
||||||
precision: CountIs(10),
|
width: CountIsParam(10),
|
||||||
width: CountIsParam(10),
|
precision_span: None,
|
||||||
precision_span: None,
|
width_span: Some(InnerSpan::new(3, 6)),
|
||||||
width_span: Some(InnerSpan::new(3, 6)),
|
ty: "x",
|
||||||
ty: "x",
|
ty_span: None,
|
||||||
ty_span: None,
|
},
|
||||||
},
|
})],
|
||||||
})],
|
);
|
||||||
);
|
same(
|
||||||
same(
|
"{:.*x}",
|
||||||
"{:.*x}",
|
&[NextArgument(Argument {
|
||||||
&[NextArgument(Argument {
|
position: ArgumentImplicitlyIs(1),
|
||||||
position: ArgumentImplicitlyIs(1),
|
format: FormatSpec {
|
||||||
format: FormatSpec {
|
fill: None,
|
||||||
fill: None,
|
align: AlignUnknown,
|
||||||
align: AlignUnknown,
|
flags: 0,
|
||||||
flags: 0,
|
precision: CountIsParam(0),
|
||||||
precision: CountIsParam(0),
|
width: CountImplied,
|
||||||
width: CountImplied,
|
precision_span: Some(InnerSpan::new(3, 5)),
|
||||||
precision_span: Some(InnerSpan::new(3, 5)),
|
width_span: None,
|
||||||
width_span: None,
|
ty: "x",
|
||||||
ty: "x",
|
ty_span: None,
|
||||||
ty_span: None,
|
},
|
||||||
},
|
})],
|
||||||
})],
|
);
|
||||||
);
|
same(
|
||||||
same(
|
"{:.10$x}",
|
||||||
"{:.10$x}",
|
&[NextArgument(Argument {
|
||||||
&[NextArgument(Argument {
|
position: ArgumentImplicitlyIs(0),
|
||||||
position: ArgumentImplicitlyIs(0),
|
format: FormatSpec {
|
||||||
format: FormatSpec {
|
fill: None,
|
||||||
fill: None,
|
align: AlignUnknown,
|
||||||
align: AlignUnknown,
|
flags: 0,
|
||||||
flags: 0,
|
precision: CountIsParam(10),
|
||||||
precision: CountIsParam(10),
|
width: CountImplied,
|
||||||
width: CountImplied,
|
precision_span: Some(InnerSpan::new(3, 7)),
|
||||||
precision_span: Some(InnerSpan::new(3, 7)),
|
width_span: None,
|
||||||
width_span: None,
|
ty: "x",
|
||||||
ty: "x",
|
ty_span: None,
|
||||||
ty_span: None,
|
},
|
||||||
},
|
})],
|
||||||
})],
|
);
|
||||||
);
|
same(
|
||||||
same(
|
"{:a$.b$?}",
|
||||||
"{:a$.b$?}",
|
&[NextArgument(Argument {
|
||||||
&[NextArgument(Argument {
|
position: ArgumentImplicitlyIs(0),
|
||||||
position: ArgumentImplicitlyIs(0),
|
format: FormatSpec {
|
||||||
format: FormatSpec {
|
fill: None,
|
||||||
fill: None,
|
align: AlignUnknown,
|
||||||
align: AlignUnknown,
|
flags: 0,
|
||||||
flags: 0,
|
precision: CountIsName("b", InnerSpan::new(6, 7)),
|
||||||
precision: CountIsName(Symbol::intern("b"), InnerSpan::new(6, 7)),
|
width: CountIsName("a", InnerSpan::new(4, 4)),
|
||||||
width: CountIsName(Symbol::intern("a"), InnerSpan::new(4, 4)),
|
precision_span: None,
|
||||||
precision_span: None,
|
width_span: None,
|
||||||
width_span: None,
|
ty: "?",
|
||||||
ty: "?",
|
ty_span: None,
|
||||||
ty_span: None,
|
},
|
||||||
},
|
})],
|
||||||
})],
|
);
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn format_flags() {
|
fn format_flags() {
|
||||||
|
@ -304,42 +304,40 @@ impl<'tcx> OnUnimplementedFormatString {
|
|||||||
match token {
|
match token {
|
||||||
Piece::String(_) => (), // Normal string, no need to check it
|
Piece::String(_) => (), // Normal string, no need to check it
|
||||||
Piece::NextArgument(a) => match a.position {
|
Piece::NextArgument(a) => match a.position {
|
||||||
// `{Self}` is allowed
|
|
||||||
Position::ArgumentNamed(s, _) if s == kw::SelfUpper => (),
|
|
||||||
// `{ThisTraitsName}` is allowed
|
|
||||||
Position::ArgumentNamed(s, _) if s == trait_name => (),
|
|
||||||
// `{from_method}` is allowed
|
|
||||||
Position::ArgumentNamed(s, _) if s == sym::from_method => (),
|
|
||||||
// `{from_desugaring}` is allowed
|
|
||||||
Position::ArgumentNamed(s, _) if s == sym::from_desugaring => (),
|
|
||||||
// `{ItemContext}` is allowed
|
|
||||||
Position::ArgumentNamed(s, _) if s == sym::ItemContext => (),
|
|
||||||
// `{integral}` and `{integer}` and `{float}` are allowed
|
|
||||||
Position::ArgumentNamed(s, _)
|
|
||||||
if s == sym::integral || s == sym::integer_ || s == sym::float =>
|
|
||||||
{
|
|
||||||
()
|
|
||||||
}
|
|
||||||
// So is `{A}` if A is a type parameter
|
|
||||||
Position::ArgumentNamed(s, _) => {
|
Position::ArgumentNamed(s, _) => {
|
||||||
match generics.params.iter().find(|param| param.name == s) {
|
match Symbol::intern(s) {
|
||||||
Some(_) => (),
|
// `{Self}` is allowed
|
||||||
None => {
|
kw::SelfUpper => (),
|
||||||
let reported = struct_span_err!(
|
// `{ThisTraitsName}` is allowed
|
||||||
tcx.sess,
|
s if s == trait_name => (),
|
||||||
span,
|
// `{from_method}` is allowed
|
||||||
E0230,
|
sym::from_method => (),
|
||||||
"there is no parameter `{}` on {}",
|
// `{from_desugaring}` is allowed
|
||||||
s,
|
sym::from_desugaring => (),
|
||||||
if trait_def_id == item_def_id {
|
// `{ItemContext}` is allowed
|
||||||
format!("trait `{}`", trait_name)
|
sym::ItemContext => (),
|
||||||
} else {
|
// `{integral}` and `{integer}` and `{float}` are allowed
|
||||||
"impl".to_string()
|
sym::integral | sym::integer_ | sym::float => (),
|
||||||
}
|
// So is `{A}` if A is a type parameter
|
||||||
)
|
s => match generics.params.iter().find(|param| param.name == s) {
|
||||||
.emit();
|
Some(_) => (),
|
||||||
result = Err(reported);
|
None => {
|
||||||
}
|
let reported = struct_span_err!(
|
||||||
|
tcx.sess,
|
||||||
|
span,
|
||||||
|
E0230,
|
||||||
|
"there is no parameter `{}` on {}",
|
||||||
|
s,
|
||||||
|
if trait_def_id == item_def_id {
|
||||||
|
format!("trait `{}`", trait_name)
|
||||||
|
} else {
|
||||||
|
"impl".to_string()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
result = Err(reported);
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// `{:1}` and `{}` are not to be used
|
// `{:1}` and `{}` are not to be used
|
||||||
@ -392,34 +390,37 @@ impl<'tcx> OnUnimplementedFormatString {
|
|||||||
.map(|p| match p {
|
.map(|p| match p {
|
||||||
Piece::String(s) => s,
|
Piece::String(s) => s,
|
||||||
Piece::NextArgument(a) => match a.position {
|
Piece::NextArgument(a) => match a.position {
|
||||||
Position::ArgumentNamed(s, _) => match generic_map.get(&s) {
|
Position::ArgumentNamed(s, _) => {
|
||||||
Some(val) => val,
|
let s = Symbol::intern(s);
|
||||||
None if s == name => &trait_str,
|
match generic_map.get(&s) {
|
||||||
None => {
|
Some(val) => val,
|
||||||
if let Some(val) = options.get(&s) {
|
None if s == name => &trait_str,
|
||||||
val
|
None => {
|
||||||
} else if s == sym::from_desugaring || s == sym::from_method {
|
if let Some(val) = options.get(&s) {
|
||||||
// don't break messages using these two arguments incorrectly
|
val
|
||||||
&empty_string
|
} else if s == sym::from_desugaring || s == sym::from_method {
|
||||||
} else if s == sym::ItemContext {
|
// don't break messages using these two arguments incorrectly
|
||||||
&item_context
|
&empty_string
|
||||||
} else if s == sym::integral {
|
} else if s == sym::ItemContext {
|
||||||
"{integral}"
|
&item_context
|
||||||
} else if s == sym::integer_ {
|
} else if s == sym::integral {
|
||||||
"{integer}"
|
"{integral}"
|
||||||
} else if s == sym::float {
|
} else if s == sym::integer_ {
|
||||||
"{float}"
|
"{integer}"
|
||||||
} else {
|
} else if s == sym::float {
|
||||||
bug!(
|
"{float}"
|
||||||
"broken on_unimplemented {:?} for {:?}: \
|
} else {
|
||||||
|
bug!(
|
||||||
|
"broken on_unimplemented {:?} for {:?}: \
|
||||||
no argument matching {:?}",
|
no argument matching {:?}",
|
||||||
self.0,
|
self.0,
|
||||||
trait_ref,
|
trait_ref,
|
||||||
s
|
s
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => bug!("broken on_unimplemented {:?} - bad format arg", self.0),
|
_ => bug!("broken on_unimplemented {:?} - bad format arg", self.0),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -13,7 +13,7 @@ use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
|||||||
use rustc_parse::parser;
|
use rustc_parse::parser;
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
use rustc_span::symbol::{kw, Symbol};
|
use rustc_span::symbol::{kw, Symbol};
|
||||||
use rustc_span::{sym, BytePos, Span, DUMMY_SP};
|
use rustc_span::{sym, BytePos, InnerSpan, Span, DUMMY_SP};
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
@ -454,6 +454,7 @@ impl SimpleFormatArgs {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
ArgumentNamed(n, _) => {
|
ArgumentNamed(n, _) => {
|
||||||
|
let n = Symbol::intern(n);
|
||||||
if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) {
|
if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) {
|
||||||
match x.1.as_slice() {
|
match x.1.as_slice() {
|
||||||
// A non-empty format string has been seen already.
|
// A non-empty format string has been seen already.
|
||||||
@ -495,7 +496,7 @@ impl Write {
|
|||||||
let span = parser
|
let span = parser
|
||||||
.arg_places
|
.arg_places
|
||||||
.last()
|
.last()
|
||||||
.map_or(DUMMY_SP, |&x| str_lit.span.from_inner(x));
|
.map_or(DUMMY_SP, |&x| str_lit.span.from_inner(InnerSpan::new(x.start, x.end)));
|
||||||
|
|
||||||
if !self.in_debug_impl && arg.format.ty == "?" {
|
if !self.in_debug_impl && arg.format.ty == "?" {
|
||||||
// FIXME: modify rustc's fmt string parser to give us the current span
|
// FIXME: modify rustc's fmt string parser to give us the current span
|
||||||
|
Loading…
Reference in New Issue
Block a user