Do not manually craft a span pointing inside a multibyte character.

This commit is contained in:
Camille GILLOT 2022-08-07 12:36:54 +02:00
parent 55f46419af
commit db7ddc50b6
3 changed files with 96 additions and 46 deletions

View File

@ -11,7 +11,7 @@ use rustc_middle::ty::adjustment;
use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::Symbol;
use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, Span, DUMMY_SP};
use rustc_span::{BytePos, Span};
declare_lint! {
/// The `unused_must_use` lint detects unused result of a type flagged as
@ -504,23 +504,23 @@ trait UnusedDelimLint {
ast::ExprKind::Block(ref block, None) if block.stmts.len() > 0 => {
let start = block.stmts[0].span;
let end = block.stmts[block.stmts.len() - 1].span;
if value.span.from_expansion() || start.from_expansion() || end.from_expansion() {
(
value.span.with_hi(value.span.lo() + BytePos(1)),
value.span.with_lo(value.span.hi() - BytePos(1)),
)
if let Some(start) = start.find_ancestor_inside(value.span)
&& let Some(end) = end.find_ancestor_inside(value.span)
{
Some((
value.span.with_hi(start.lo()),
value.span.with_lo(end.hi()),
))
} else {
(value.span.with_hi(start.lo()), value.span.with_lo(end.hi()))
None
}
}
ast::ExprKind::Paren(ref expr) => {
if value.span.from_expansion() || expr.span.from_expansion() {
(
value.span.with_hi(value.span.lo() + BytePos(1)),
value.span.with_lo(value.span.hi() - BytePos(1)),
)
let expr_span = expr.span.find_ancestor_inside(value.span);
if let Some(expr_span) = expr_span {
Some((value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi())))
} else {
(value.span.with_hi(expr.span.lo()), value.span.with_lo(expr.span.hi()))
None
}
}
_ => return,
@ -529,36 +529,38 @@ trait UnusedDelimLint {
left_pos.map_or(false, |s| s >= value.span.lo()),
right_pos.map_or(false, |s| s <= value.span.hi()),
);
self.emit_unused_delims(cx, spans, ctx.into(), keep_space);
self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space);
}
fn emit_unused_delims(
&self,
cx: &EarlyContext<'_>,
spans: (Span, Span),
value_span: Span,
spans: Option<(Span, Span)>,
msg: &str,
keep_space: (bool, bool),
) {
// FIXME(flip1995): Quick and dirty fix for #70814. This should be fixed in rustdoc
// properly.
if spans.0 == DUMMY_SP || spans.1 == DUMMY_SP {
return;
}
cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| {
let replacement = vec![
(spans.0, if keep_space.0 { " ".into() } else { "".into() }),
(spans.1, if keep_space.1 { " ".into() } else { "".into() }),
];
lint.build(fluent::lint::unused_delim)
.set_arg("delim", Self::DELIM_STR)
.set_arg("item", msg)
.multipart_suggestion(
let primary_span = if let Some((lo, hi)) = spans {
MultiSpan::from(vec![lo, hi])
} else {
MultiSpan::from(value_span)
};
cx.struct_span_lint(self.lint(), primary_span, |lint| {
let mut db = lint.build(fluent::lint::unused_delim);
db.set_arg("delim", Self::DELIM_STR);
db.set_arg("item", msg);
if let Some((lo, hi)) = spans {
let replacement = vec![
(lo, if keep_space.0 { " ".into() } else { "".into() }),
(hi, if keep_space.1 { " ".into() } else { "".into() }),
];
db.multipart_suggestion(
fluent::lint::suggestion,
replacement,
Applicability::MachineApplicable,
)
.emit();
);
}
db.emit();
});
}
@ -766,15 +768,12 @@ impl UnusedParens {
// Otherwise proceed with linting.
_ => {}
}
let spans = if value.span.from_expansion() || inner.span.from_expansion() {
(
value.span.with_hi(value.span.lo() + BytePos(1)),
value.span.with_lo(value.span.hi() - BytePos(1)),
)
let spans = if let Some(inner) = inner.span.find_ancestor_inside(value.span) {
Some((value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())))
} else {
(value.span.with_hi(inner.span.lo()), value.span.with_lo(inner.span.hi()))
None
};
self.emit_unused_delims(cx, spans, "pattern", (false, false));
self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false));
}
}
}
@ -879,15 +878,12 @@ impl EarlyLintPass for UnusedParens {
);
}
_ => {
let spans = if ty.span.from_expansion() || r.span.from_expansion() {
(
ty.span.with_hi(ty.span.lo() + BytePos(1)),
ty.span.with_lo(ty.span.hi() - BytePos(1)),
)
let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) {
Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
} else {
(ty.span.with_hi(r.span.lo()), ty.span.with_lo(r.span.hi()))
None
};
self.emit_unused_delims(cx, spans, "type", (false, false));
self.emit_unused_delims(cx, ty.span, spans, "type", (false, false));
}
}
}

View File

@ -0,0 +1,11 @@
// ignore-tidy-trailing-newlines
//
// error-pattern: this file contains an unclosed delimiter
// error-pattern: this file contains an unclosed delimiter
// error-pattern: this file contains an unclosed delimiter
// error-pattern: format argument must be a string literal
//
// Verify that unused parens lint does not try to create a span
// which points in the middle of a multibyte character.
fn f(){(print!(á

View File

@ -0,0 +1,43 @@
error: this file contains an unclosed delimiter
--> $DIR/unused_parens_multibyte_recovery.rs:11:17
|
LL | fn f(){(print!(á
| -- - ^
| || |
| || unclosed delimiter
| |unclosed delimiter
| unclosed delimiter
error: this file contains an unclosed delimiter
--> $DIR/unused_parens_multibyte_recovery.rs:11:17
|
LL | fn f(){(print!(á
| -- - ^
| || |
| || unclosed delimiter
| |unclosed delimiter
| unclosed delimiter
error: this file contains an unclosed delimiter
--> $DIR/unused_parens_multibyte_recovery.rs:11:17
|
LL | fn f(){(print!(á
| -- - ^
| || |
| || unclosed delimiter
| |unclosed delimiter
| unclosed delimiter
error: format argument must be a string literal
--> $DIR/unused_parens_multibyte_recovery.rs:11:16
|
LL | fn f(){(print!(á
| ^
|
help: you might be missing a string literal to format with
|
LL | fn f(){(print!("{}", á
| +++++
error: aborting due to 4 previous errors