lint: port non-fmt-panic diagnostics
Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
parent
48e4bf115f
commit
7ee4aa7003
5 changed files with 132 additions and 91 deletions
|
@ -1,6 +1,6 @@
|
|||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_ast as ast;
|
||||
use rustc_errors::{pluralize, Applicability};
|
||||
use rustc_errors::{fluent, Applicability};
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
|
@ -120,9 +120,10 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
|||
}
|
||||
|
||||
cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| {
|
||||
let mut l = lint.build("panic message is not a string literal");
|
||||
l.note(&format!("this usage of {}!() is deprecated; it will be a hard error in Rust 2021", symbol));
|
||||
l.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>");
|
||||
let mut l = lint.build(fluent::lint::non_fmt_panic);
|
||||
l.set_arg("name", symbol);
|
||||
l.note(fluent::lint::note);
|
||||
l.note(fluent::lint::more_info_note);
|
||||
if !is_arg_inside_call(arg_span, span) {
|
||||
// No clue where this argument is coming from.
|
||||
l.emit();
|
||||
|
@ -130,10 +131,10 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
|||
}
|
||||
if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
|
||||
// A case of `panic!(format!(..))`.
|
||||
l.note(format!("the {}!() macro supports formatting, so there's no need for the format!() macro here", symbol).as_str());
|
||||
l.note(fluent::lint::supports_fmt_note);
|
||||
if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
|
||||
l.multipart_suggestion(
|
||||
"remove the `format!(..)` macro call",
|
||||
fluent::lint::supports_fmt_suggestion,
|
||||
vec![
|
||||
(arg_span.until(open.shrink_to_hi()), "".into()),
|
||||
(close.until(arg_span.shrink_to_hi()), "".into()),
|
||||
|
@ -153,12 +154,18 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
|||
);
|
||||
|
||||
let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| {
|
||||
let display = is_str || cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
|
||||
infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
|
||||
}) == Some(true);
|
||||
let debug = !display && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
|
||||
infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
|
||||
}) == Some(true);
|
||||
let display = is_str
|
||||
|| cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
|
||||
infcx
|
||||
.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
|
||||
.may_apply()
|
||||
}) == Some(true);
|
||||
let debug = !display
|
||||
&& cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
|
||||
infcx
|
||||
.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
|
||||
.may_apply()
|
||||
}) == Some(true);
|
||||
(display, debug)
|
||||
});
|
||||
|
||||
|
@ -175,17 +182,15 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
|||
if suggest_display {
|
||||
l.span_suggestion_verbose(
|
||||
arg_span.shrink_to_lo(),
|
||||
"add a \"{}\" format string to Display the message",
|
||||
fluent::lint::display_suggestion,
|
||||
"\"{}\", ",
|
||||
fmt_applicability,
|
||||
);
|
||||
} else if suggest_debug {
|
||||
l.set_arg("ty", ty);
|
||||
l.span_suggestion_verbose(
|
||||
arg_span.shrink_to_lo(),
|
||||
&format!(
|
||||
"add a \"{{:?}}\" format string to use the Debug implementation of `{}`",
|
||||
ty,
|
||||
),
|
||||
fluent::lint::debug_suggestion,
|
||||
"\"{:?}\", ",
|
||||
fmt_applicability,
|
||||
);
|
||||
|
@ -193,15 +198,9 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
|||
|
||||
if suggest_panic_any {
|
||||
if let Some((open, close, del)) = find_delimiters(cx, span) {
|
||||
l.set_arg("already_suggested", suggest_display || suggest_debug);
|
||||
l.multipart_suggestion(
|
||||
&format!(
|
||||
"{}use std::panic::panic_any instead",
|
||||
if suggest_display || suggest_debug {
|
||||
"or "
|
||||
} else {
|
||||
""
|
||||
},
|
||||
),
|
||||
fluent::lint::panic_suggestion,
|
||||
if del == '(' {
|
||||
vec![(span.until(open), "std::panic::panic_any".into())]
|
||||
} else {
|
||||
|
@ -260,21 +259,19 @@ fn check_panic_str<'tcx>(
|
|||
.collect(),
|
||||
};
|
||||
cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
|
||||
let mut l = lint.build(match n_arguments {
|
||||
1 => "panic message contains an unused formatting placeholder",
|
||||
_ => "panic message contains unused formatting placeholders",
|
||||
});
|
||||
l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021");
|
||||
let mut l = lint.build(fluent::lint::non_fmt_panic_unused);
|
||||
l.set_arg("count", n_arguments);
|
||||
l.note(fluent::lint::note);
|
||||
if is_arg_inside_call(arg.span, span) {
|
||||
l.span_suggestion(
|
||||
arg.span.shrink_to_hi(),
|
||||
&format!("add the missing argument{}", pluralize!(n_arguments)),
|
||||
fluent::lint::add_args_suggestion,
|
||||
", ...",
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
l.span_suggestion(
|
||||
arg.span.shrink_to_lo(),
|
||||
"or add a \"{}\" format string to use the message literally",
|
||||
fluent::lint::add_fmt_suggestion,
|
||||
"\"{}\", ",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
@ -289,17 +286,15 @@ fn check_panic_str<'tcx>(
|
|||
.map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 }))
|
||||
.collect()
|
||||
});
|
||||
let msg = match &brace_spans {
|
||||
Some(v) if v.len() == 1 => "panic message contains a brace",
|
||||
_ => "panic message contains braces",
|
||||
};
|
||||
let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2);
|
||||
cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| {
|
||||
let mut l = lint.build(msg);
|
||||
l.note("this message is not used as a format string, but will be in Rust 2021");
|
||||
let mut l = lint.build(fluent::lint::non_fmt_panic_braces);
|
||||
l.set_arg("count", count);
|
||||
l.note(fluent::lint::note);
|
||||
if is_arg_inside_call(arg.span, span) {
|
||||
l.span_suggestion(
|
||||
arg.span.shrink_to_lo(),
|
||||
"add a \"{}\" format string to use the message literally",
|
||||
fluent::lint::suggestion,
|
||||
"\"{}\", ",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue