Auto merge of #101986 - WaffleLapkin:move_lint_note_to_the_bottom, r=estebank

Move lint level source explanation to the bottom

So, uhhhhh

r? `@estebank`

## User-facing change

"note: `#[warn(...)]` on by default" and such are moved to the bottom of the diagnostic:
```diff
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
```

Why warning is enabled is the least important thing, so it shouldn't be the first note the user reads, IMO.

## Developer-facing change

`struct_span_lint` and similar methods have a different signature.

Before: `..., impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>)`
After: `..., impl Into<DiagnosticMessage>, impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>) -> &'b mut DiagnosticBuilder<'a, ()>`

The reason for this is that `struct_span_lint` needs to edit the diagnostic _after_ `decorate` closure is called. This also makes lint code a little bit nicer in my opinion.

Another option is to use `impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>) -> DiagnosticBuilder<'a, ()>` altough I don't _really_ see reasons to do `let lint = lint.build(message)` everywhere.

## Subtle problem

By moving the message outside of the closure (that may not be called if the lint is disabled) `format!(...)` is executed earlier, possibly formatting `Ty` which may call a query that trims paths that crashes the compiler if there were no warnings...

I don't think it's that big of a deal, considering that we move from `format!(...)` to `fluent` (which is lazy by-default) anyway, however this required adding a workaround which is unfortunate.

## P.S.

I'm sorry, I do not how to make this PR smaller/easier to review. Changes to the lint API affect SO MUCH 😢
This commit is contained in:
bors 2022-10-01 10:44:25 +00:00
commit 744e397d88
827 changed files with 3370 additions and 3210 deletions

View file

@ -370,10 +370,13 @@ impl CheckAttrVisitor<'_> {
b.push_str(&(allowed_target.to_string() + "s"));
b
});
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
lint.build(&format!("`#[{name}]` only has an effect on {}", supported_names))
.emit();
});
self.tcx.struct_span_lint_hir(
UNUSED_ATTRIBUTES,
hir_id,
attr.span,
&format!("`#[{name}]` only has an effect on {}", supported_names),
|lint| lint,
);
}
}
@ -877,25 +880,31 @@ impl CheckAttrVisitor<'_> {
hir_id: HirId,
) -> bool {
if hir_id != CRATE_HIR_ID {
self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| {
let mut err = lint.build(fluent::passes::attr_crate_level);
if attr.style == AttrStyle::Outer
&& self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID
{
if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) {
src.insert(1, '!');
err.span_suggestion_verbose(
attr.span,
fluent::passes::suggestion,
src,
Applicability::MaybeIncorrect,
);
} else {
err.span_help(attr.span, fluent::passes::help);
self.tcx.struct_span_lint_hir(
INVALID_DOC_ATTRIBUTES,
hir_id,
meta.span(),
fluent::passes::attr_crate_level,
|err| {
if attr.style == AttrStyle::Outer
&& self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID
{
if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) {
src.insert(1, '!');
err.span_suggestion_verbose(
attr.span,
fluent::passes::suggestion,
src,
Applicability::MaybeIncorrect,
);
} else {
err.span_help(attr.span, fluent::passes::help);
}
}
}
err.note(fluent::passes::note).emit();
});
err.note(fluent::passes::note);
err
},
);
return false;
}
true

View file

@ -4,7 +4,7 @@
use itertools::Itertools;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, Applicability, MultiSpan};
use rustc_errors::{pluralize, Applicability, DelayDm, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
@ -184,13 +184,14 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
lint::builtin::DEAD_CODE,
assign.hir_id,
assign.span,
|lint| {
lint.build(&format!(
DelayDm(|| format!(
"useless assignment of {} of type `{}` to itself",
if is_field_assign { "field" } else { "variable" },
self.typeck_results().expr_ty(lhs),
))
.emit();
)),
|lint| {
lint
},
)
}
@ -717,6 +718,26 @@ impl<'tcx> DeadVisitor<'tcx> {
})
.collect();
let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
let span_len = dead_codes.len();
let names = match &names[..] {
_ if span_len > 6 => String::new(),
[name] => format!("`{name}` "),
[names @ .., last] => {
format!(
"{} and `{last}` ",
names.iter().map(|name| format!("`{name}`")).join(", ")
)
}
[] => unreachable!(),
};
let msg = format!(
"{these}{descr}{s} {names}{are} never {participle}",
these = if span_len > 6 { "multiple " } else { "" },
s = pluralize!(span_len),
are = pluralize!("is", span_len),
);
tcx.struct_span_lint_hir(
if is_positional {
lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
@ -725,27 +746,8 @@ impl<'tcx> DeadVisitor<'tcx> {
},
tcx.hir().local_def_id_to_hir_id(first_id),
MultiSpan::from_spans(spans.clone()),
|lint| {
let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
let span_len = dead_codes.len();
let names = match &names[..] {
_ if span_len > 6 => String::new(),
[name] => format!("`{name}` "),
[names @ .., last] => {
format!(
"{} and `{last}` ",
names.iter().map(|name| format!("`{name}`")).join(", ")
)
}
[] => unreachable!(),
};
let mut err = lint.build(&format!(
"{these}{descr}{s} {names}{are} never {participle}",
these = if span_len > 6 { "multiple " } else { "" },
s = pluralize!(span_len),
are = pluralize!("is", span_len),
));
msg,
|err| {
if is_positional {
err.multipart_suggestion(
&format!(
@ -791,7 +793,7 @@ impl<'tcx> DeadVisitor<'tcx> {
);
err.note(&msg);
}
err.emit();
err
},
);
}

View file

@ -1319,14 +1319,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// that we do not emit the same warning twice if the uninhabited type
// is indeed `!`.
let msg = format!("unreachable {}", descr);
self.ir.tcx.struct_span_lint_hir(
lint::builtin::UNREACHABLE_CODE,
expr_id,
expr_span,
|lint| {
let msg = format!("unreachable {}", descr);
lint.build(&msg)
.span_label(expr_span, &msg)
&msg,
|diag| {
diag.span_label(expr_span, &msg)
.span_label(orig_span, "any code following this expression is unreachable")
.span_note(
orig_span,
@ -1335,7 +1335,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
orig_ty
),
)
.emit();
},
);
}
@ -1491,14 +1490,8 @@ impl<'tcx> Liveness<'_, 'tcx> {
lint::builtin::UNUSED_ASSIGNMENTS,
var_hir_id,
vec![span],
|lint| {
lint.build(&format!(
"value captured by `{}` is never read",
name
))
.help("did you mean to capture by reference instead?")
.emit();
},
format!("value captured by `{}` is never read", name),
|lint| lint.help("did you mean to capture by reference instead?"),
);
}
}
@ -1508,11 +1501,8 @@ impl<'tcx> Liveness<'_, 'tcx> {
lint::builtin::UNUSED_VARIABLES,
var_hir_id,
vec![span],
|lint| {
lint.build(&format!("unused variable: `{}`", name))
.help("did you mean to capture by reference instead?")
.emit();
},
format!("unused variable: `{}`", name),
|lint| lint.help("did you mean to capture by reference instead?"),
);
}
}
@ -1601,20 +1591,17 @@ impl<'tcx> Liveness<'_, 'tcx> {
.into_iter()
.map(|(_, _, ident_span)| ident_span)
.collect::<Vec<_>>(),
|lint| {
lint.build(&format!("variable `{}` is assigned to, but never used", name))
.note(&format!("consider using `_{}` instead", name))
.emit();
},
format!("variable `{}` is assigned to, but never used", name),
|lint| lint.note(&format!("consider using `_{}` instead", name)),
)
} else if can_remove {
self.ir.tcx.struct_span_lint_hir(
lint::builtin::UNUSED_VARIABLES,
first_hir_id,
hir_ids_and_spans.iter().map(|(_, pat_span, _)| *pat_span).collect::<Vec<_>>(),
format!("unused variable: `{}`", name),
|lint| {
let mut err = lint.build(&format!("unused variable: `{}`", name));
err.multipart_suggestion(
lint.multipart_suggestion(
"try removing the field",
hir_ids_and_spans
.iter()
@ -1629,8 +1616,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
})
.collect(),
Applicability::MachineApplicable,
);
err.emit();
)
},
);
} else {
@ -1661,14 +1647,13 @@ impl<'tcx> Liveness<'_, 'tcx> {
.iter()
.map(|(_, pat_span, _)| *pat_span)
.collect::<Vec<_>>(),
format!("unused variable: `{}`", name),
|lint| {
let mut err = lint.build(&format!("unused variable: `{}`", name));
err.multipart_suggestion(
lint.multipart_suggestion(
"try ignoring the field",
shorthands,
Applicability::MachineApplicable,
);
err.emit();
)
},
);
} else {
@ -1684,17 +1669,16 @@ impl<'tcx> Liveness<'_, 'tcx> {
.iter()
.map(|(_, _, ident_span)| *ident_span)
.collect::<Vec<_>>(),
format!("unused variable: `{}`", name),
|lint| {
let mut err = lint.build(&format!("unused variable: `{}`", name));
if self.has_added_lit_match_name_span(&name, opt_body, &mut err) {
err.span_label(pat.span, "unused variable");
if self.has_added_lit_match_name_span(&name, opt_body, lint) {
lint.span_label(pat.span, "unused variable");
}
err.multipart_suggestion(
lint.multipart_suggestion(
"if this is intentional, prefix it with an underscore",
non_shorthands,
Applicability::MachineApplicable,
);
err.emit();
)
},
);
}
@ -1758,11 +1742,8 @@ impl<'tcx> Liveness<'_, 'tcx> {
lint::builtin::UNUSED_ASSIGNMENTS,
hir_id,
spans,
|lint| {
lint.build(&message(&name))
.help("maybe it is overwritten before being read?")
.emit();
},
message(&name),
|lint| lint.help("maybe it is overwritten before being read?"),
)
}
}

View file

@ -65,9 +65,13 @@ fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
if abi == Abi::Rust {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let span = tcx.def_span(def_id);
tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, span, |lint| {
lint.build("Rust ABI is unsupported in naked functions").emit();
});
tcx.struct_span_lint_hir(
UNDEFINED_NAKED_FUNCTION_ABI,
hir_id,
span,
"Rust ABI is unsupported in naked functions",
|lint| lint,
);
}
}

View file

@ -752,10 +752,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
item.hir_id(),
span,
|lint| {lint
.build("an `#[unstable]` annotation here has no effect")
.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
.emit();}
"an `#[unstable]` annotation here has no effect",
|lint| lint.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
);
}
}
@ -1081,11 +1079,16 @@ fn unnecessary_partially_stable_feature_lint(
implies: Symbol,
since: Symbol,
) {
tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
lint.build(&format!(
tcx.struct_span_lint_hir(
lint::builtin::STABLE_FEATURES,
hir::CRATE_HIR_ID,
span,
format!(
"the feature `{feature}` has been partially stabilized since {since} and is succeeded \
by the feature `{implies}`"
))
),
|lint| {
lint
.span_suggestion(
span,
&format!(
@ -1100,8 +1103,8 @@ fn unnecessary_partially_stable_feature_lint(
"",
Applicability::MaybeIncorrect,
)
.emit();
});
},
);
}
fn unnecessary_stable_feature_lint(
@ -1113,12 +1116,8 @@ fn unnecessary_stable_feature_lint(
if since.as_str() == VERSION_PLACEHOLDER {
since = rust_version_symbol();
}
tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
lint.build(&format!(
"the feature `{feature}` has been stable since {since} and no longer requires an \
attribute to enable",
))
.emit();
tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, format!("the feature `{feature}` has been stable since {since} and no longer requires an attribute to enable"), |lint| {
lint
});
}