Auto merge of #125410 - fmease:adj-lint-diag-api, r=nnethercote
[perf] Delay the construction of early lint diag structs
Attacks some of the perf regressions from https://github.com/rust-lang/rust/pull/124417#issuecomment-2123700666.
See individual commits for details. The first three commits are not strictly necessary.
However, the 2nd one (06bc4fc671, *Remove `LintDiagnostic::msg`*) makes the main change way nicer to implement.
It's also pretty sweet on its own if I may say so myself.
This commit is contained in:
commit
b582f807fa
50 changed files with 598 additions and 749 deletions
|
|
@ -372,8 +372,8 @@ pub(crate) fn run_global_ctxt(
|
|||
tcx.node_lint(
|
||||
crate::lint::MISSING_CRATE_LEVEL_DOCS,
|
||||
DocContext::as_local_hir_id(tcx, krate.module.item_id).unwrap(),
|
||||
"no documentation found for this crate's top-level module",
|
||||
|lint| {
|
||||
lint.primary_message("no documentation found for this crate's top-level module");
|
||||
lint.help(help);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -834,8 +834,9 @@ impl<'tcx> ExtraInfo<'tcx> {
|
|||
crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
|
||||
self.tcx.local_def_id_to_hir_id(def_id),
|
||||
self.sp,
|
||||
msg,
|
||||
|_| {},
|
||||
|lint| {
|
||||
lint.primary_message(msg);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -850,8 +851,10 @@ impl<'tcx> ExtraInfo<'tcx> {
|
|||
crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
|
||||
self.tcx.local_def_id_to_hir_id(def_id),
|
||||
self.sp,
|
||||
msg,
|
||||
f,
|
||||
|lint| {
|
||||
lint.primary_message(msg);
|
||||
f(lint);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,13 +125,9 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item
|
|||
if should_have_doc_example(cx, item) {
|
||||
debug!("reporting error for {item:?} (hir_id={hir_id:?})");
|
||||
let sp = item.attr_span(cx.tcx);
|
||||
cx.tcx.node_span_lint(
|
||||
crate::lint::MISSING_DOC_CODE_EXAMPLES,
|
||||
hir_id,
|
||||
sp,
|
||||
"missing code example in this documentation",
|
||||
|_| {},
|
||||
);
|
||||
cx.tcx.node_span_lint(crate::lint::MISSING_DOC_CODE_EXAMPLES, hir_id, sp, |lint| {
|
||||
lint.primary_message("missing code example in this documentation");
|
||||
});
|
||||
}
|
||||
} else if tests.found_tests > 0
|
||||
&& !cx.cache.effective_visibilities.is_exported(cx.tcx, item.item_id.expect_def_id())
|
||||
|
|
@ -140,8 +136,9 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item
|
|||
crate::lint::PRIVATE_DOC_TESTS,
|
||||
hir_id,
|
||||
item.attr_span(cx.tcx),
|
||||
"documentation test in private item",
|
||||
|_| {},
|
||||
|lint| {
|
||||
lint.primary_message("documentation test in private item");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1689,7 +1689,9 @@ fn report_diagnostic(
|
|||
|
||||
let sp = item.attr_span(tcx);
|
||||
|
||||
tcx.node_span_lint(lint, hir_id, sp, msg, |lint| {
|
||||
tcx.node_span_lint(lint, hir_id, sp, |lint| {
|
||||
lint.primary_message(msg);
|
||||
|
||||
let (span, link_range) = match link_range {
|
||||
MarkdownLinkRange::Destination(md_range) => {
|
||||
let mut md_range = md_range.clone();
|
||||
|
|
|
|||
|
|
@ -24,8 +24,9 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item) {
|
|||
let sp =
|
||||
source_span_for_markdown_range(cx.tcx, &dox, &range, &item.attrs.doc_strings)
|
||||
.unwrap_or_else(|| item.attr_span(cx.tcx));
|
||||
cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, msg, |lint| {
|
||||
lint.note("bare URLs are not automatically turned into clickable links")
|
||||
cx.tcx.node_span_lint(crate::lint::BARE_URLS, hir_id, sp, |lint| {
|
||||
lint.primary_message(msg)
|
||||
.note("bare URLs are not automatically turned into clickable links")
|
||||
.span_suggestion(
|
||||
sp,
|
||||
"use an automatic link instead",
|
||||
|
|
|
|||
|
|
@ -99,7 +99,9 @@ fn check_rust_syntax(
|
|||
// All points of divergence have been handled earlier so this can be
|
||||
// done the same way whether the span is precise or not.
|
||||
let hir_id = cx.tcx.local_def_id_to_hir_id(local_id);
|
||||
cx.tcx.node_span_lint(crate::lint::INVALID_RUST_CODEBLOCKS, hir_id, sp, msg, |lint| {
|
||||
cx.tcx.node_span_lint(crate::lint::INVALID_RUST_CODEBLOCKS, hir_id, sp, |lint| {
|
||||
lint.primary_message(msg);
|
||||
|
||||
let explanation = if is_ignore {
|
||||
"`ignore` code blocks require valid Rust code for syntax highlighting; \
|
||||
mark blocks that do not contain Rust code as text"
|
||||
|
|
|
|||
|
|
@ -25,8 +25,11 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
|
|||
Some(sp) => sp,
|
||||
None => item.attr_span(tcx),
|
||||
};
|
||||
tcx.node_span_lint(crate::lint::INVALID_HTML_TAGS, hir_id, sp, msg, |lint| {
|
||||
tcx.node_span_lint(crate::lint::INVALID_HTML_TAGS, hir_id, sp, |lint| {
|
||||
use rustc_lint_defs::Applicability;
|
||||
|
||||
lint.primary_message(msg);
|
||||
|
||||
// If a tag looks like `<this>`, it might actually be a generic.
|
||||
// We don't try to detect stuff `<like, this>` because that's not valid HTML,
|
||||
// and we don't try to detect stuff `<like this>` because that's not valid Rust.
|
||||
|
|
|
|||
|
|
@ -188,8 +188,9 @@ fn check_inline_or_reference_unknown_redundancy(
|
|||
&item.attrs.doc_strings,
|
||||
)?;
|
||||
|
||||
cx.tcx.node_span_lint(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| {
|
||||
lint.span_label(explicit_span, "explicit target is redundant")
|
||||
cx.tcx.node_span_lint(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, |lint| {
|
||||
lint.primary_message("redundant explicit link target")
|
||||
.span_label(explicit_span, "explicit target is redundant")
|
||||
.span_label(display_span, "because label contains path that resolves to same destination")
|
||||
.note("when a link's destination is not specified,\nthe label is used to resolve intra-doc links")
|
||||
.span_suggestion_with_style(link_span, "remove explicit link target", format!("[{}]", link_data.display_link), Applicability::MaybeIncorrect, SuggestionStyle::ShowAlways);
|
||||
|
|
@ -238,8 +239,9 @@ fn check_reference_redundancy(
|
|||
&item.attrs.doc_strings,
|
||||
)?;
|
||||
|
||||
cx.tcx.node_span_lint(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, "redundant explicit link target", |lint| {
|
||||
lint.span_label(explicit_span, "explicit target is redundant")
|
||||
cx.tcx.node_span_lint(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, |lint| {
|
||||
lint.primary_message("redundant explicit link target")
|
||||
.span_label(explicit_span, "explicit target is redundant")
|
||||
.span_label(display_span, "because label contains path that resolves to same destination")
|
||||
.span_note(def_span, "referenced explicit link target defined here")
|
||||
.note("when a link's destination is not specified,\nthe label is used to resolve intra-doc links")
|
||||
|
|
|
|||
|
|
@ -56,17 +56,28 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
|
|||
)
|
||||
.unwrap_or_else(|| item.attr_span(tcx));
|
||||
|
||||
tcx.node_span_lint(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, "unescaped backtick", |lint| {
|
||||
tcx.node_span_lint(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, |lint| {
|
||||
lint.primary_message("unescaped backtick");
|
||||
|
||||
let mut help_emitted = false;
|
||||
|
||||
match element.prev_code_guess {
|
||||
PrevCodeGuess::None => {}
|
||||
PrevCodeGuess::Start { guess, .. } => {
|
||||
// "foo` `bar`" -> "`foo` `bar`"
|
||||
if let Some(suggest_index) = clamp_start(guess, &element.suggestible_ranges)
|
||||
if let Some(suggest_index) =
|
||||
clamp_start(guess, &element.suggestible_ranges)
|
||||
&& can_suggest_backtick(&dox, suggest_index)
|
||||
{
|
||||
suggest_insertion(cx, item, &dox, lint, suggest_index, '`', "the opening backtick of a previous inline code may be missing");
|
||||
suggest_insertion(
|
||||
cx,
|
||||
item,
|
||||
&dox,
|
||||
lint,
|
||||
suggest_index,
|
||||
'`',
|
||||
"the opening backtick of a previous inline code may be missing",
|
||||
);
|
||||
help_emitted = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -76,7 +87,15 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
|
|||
// an inline code node and we intentionally "break" the inline code here.
|
||||
let suggest_index = guess;
|
||||
if can_suggest_backtick(&dox, suggest_index) {
|
||||
suggest_insertion(cx, item, &dox, lint, suggest_index, '`', "a previous inline code might be longer than expected");
|
||||
suggest_insertion(
|
||||
cx,
|
||||
item,
|
||||
&dox,
|
||||
lint,
|
||||
suggest_index,
|
||||
'`',
|
||||
"a previous inline code might be longer than expected",
|
||||
);
|
||||
help_emitted = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -84,11 +103,21 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
|
|||
|
||||
if !element.prev_code_guess.is_confident() {
|
||||
// "`foo` bar`" -> "`foo` `bar`"
|
||||
if let Some(guess) = guess_start_of_code(&dox, element.element_range.start..backtick_index)
|
||||
&& let Some(suggest_index) = clamp_start(guess, &element.suggestible_ranges)
|
||||
if let Some(guess) =
|
||||
guess_start_of_code(&dox, element.element_range.start..backtick_index)
|
||||
&& let Some(suggest_index) =
|
||||
clamp_start(guess, &element.suggestible_ranges)
|
||||
&& can_suggest_backtick(&dox, suggest_index)
|
||||
{
|
||||
suggest_insertion(cx, item, &dox, lint, suggest_index, '`', "the opening backtick of an inline code may be missing");
|
||||
suggest_insertion(
|
||||
cx,
|
||||
item,
|
||||
&dox,
|
||||
lint,
|
||||
suggest_index,
|
||||
'`',
|
||||
"the opening backtick of an inline code may be missing",
|
||||
);
|
||||
help_emitted = true;
|
||||
}
|
||||
|
||||
|
|
@ -96,21 +125,41 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item) {
|
|||
// Don't suggest closing backtick after single trailing char,
|
||||
// if we already suggested opening backtick. For example:
|
||||
// "foo`." -> "`foo`." or "foo`s" -> "`foo`s".
|
||||
if let Some(guess) = guess_end_of_code(&dox, backtick_index + 1..element.element_range.end)
|
||||
&& let Some(suggest_index) = clamp_end(guess, &element.suggestible_ranges)
|
||||
if let Some(guess) =
|
||||
guess_end_of_code(&dox, backtick_index + 1..element.element_range.end)
|
||||
&& let Some(suggest_index) =
|
||||
clamp_end(guess, &element.suggestible_ranges)
|
||||
&& can_suggest_backtick(&dox, suggest_index)
|
||||
&& (!help_emitted || suggest_index - backtick_index > 2)
|
||||
{
|
||||
suggest_insertion(cx, item, &dox, lint, suggest_index, '`', "the closing backtick of an inline code may be missing");
|
||||
suggest_insertion(
|
||||
cx,
|
||||
item,
|
||||
&dox,
|
||||
lint,
|
||||
suggest_index,
|
||||
'`',
|
||||
"the closing backtick of an inline code may be missing",
|
||||
);
|
||||
help_emitted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if !help_emitted {
|
||||
lint.help("the opening or closing backtick of an inline code may be missing");
|
||||
lint.help(
|
||||
"the opening or closing backtick of an inline code may be missing",
|
||||
);
|
||||
}
|
||||
|
||||
suggest_insertion(cx, item, &dox, lint, backtick_index, '\\', "if you meant to use a literal backtick, escape it");
|
||||
suggest_insertion(
|
||||
cx,
|
||||
item,
|
||||
&dox,
|
||||
lint,
|
||||
backtick_index,
|
||||
'\\',
|
||||
"if you meant to use a literal backtick, escape it",
|
||||
);
|
||||
});
|
||||
}
|
||||
Event::Code(_) => {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) {
|
|||
/// ```
|
||||
pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
|
||||
#[expect(clippy::disallowed_methods)]
|
||||
cx.span_lint(lint, sp, msg.into(), |diag| {
|
||||
cx.span_lint(lint, sp, |diag| {
|
||||
diag.primary_message(msg);
|
||||
docs_link(diag, lint);
|
||||
});
|
||||
}
|
||||
|
|
@ -109,7 +110,8 @@ pub fn span_lint_and_help<T: LintContext>(
|
|||
help: impl Into<SubdiagMessage>,
|
||||
) {
|
||||
#[expect(clippy::disallowed_methods)]
|
||||
cx.span_lint(lint, span, msg.into(), |diag| {
|
||||
cx.span_lint(lint, span, |diag| {
|
||||
diag.primary_message(msg);
|
||||
if let Some(help_span) = help_span {
|
||||
diag.span_help(help_span, help.into());
|
||||
} else {
|
||||
|
|
@ -165,7 +167,8 @@ pub fn span_lint_and_note<T: LintContext>(
|
|||
note: impl Into<SubdiagMessage>,
|
||||
) {
|
||||
#[expect(clippy::disallowed_methods)]
|
||||
cx.span_lint(lint, span, msg.into(), |diag| {
|
||||
cx.span_lint(lint, span, |diag| {
|
||||
diag.primary_message(msg);
|
||||
if let Some(note_span) = note_span {
|
||||
diag.span_note(note_span, note.into());
|
||||
} else {
|
||||
|
|
@ -201,7 +204,8 @@ where
|
|||
F: FnOnce(&mut Diag<'_, ()>),
|
||||
{
|
||||
#[expect(clippy::disallowed_methods)]
|
||||
cx.span_lint(lint, sp, msg, |diag| {
|
||||
cx.span_lint(lint, sp, |diag| {
|
||||
diag.primary_message(msg);
|
||||
f(diag);
|
||||
docs_link(diag, lint);
|
||||
});
|
||||
|
|
@ -233,7 +237,8 @@ where
|
|||
/// the `#[allow]` will work.
|
||||
pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: impl Into<DiagMessage>) {
|
||||
#[expect(clippy::disallowed_methods)]
|
||||
cx.tcx.node_span_lint(lint, hir_id, sp, msg.into(), |diag| {
|
||||
cx.tcx.node_span_lint(lint, hir_id, sp, |diag| {
|
||||
diag.primary_message(msg);
|
||||
docs_link(diag, lint);
|
||||
});
|
||||
}
|
||||
|
|
@ -271,7 +276,8 @@ pub fn span_lint_hir_and_then(
|
|||
f: impl FnOnce(&mut Diag<'_, ()>),
|
||||
) {
|
||||
#[expect(clippy::disallowed_methods)]
|
||||
cx.tcx.node_span_lint(lint, hir_id, sp, msg.into(), |diag| {
|
||||
cx.tcx.node_span_lint(lint, hir_id, sp, |diag| {
|
||||
diag.primary_message(msg);
|
||||
f(diag);
|
||||
docs_link(diag, lint);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@ use rustc_lint::{Lint, LintContext};
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
pub fn a(cx: impl LintContext, lint: &'static Lint, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
|
||||
cx.span_lint(lint, span, msg, |_| {});
|
||||
cx.span_lint(lint, span, |lint| { lint.primary_message(msg); });
|
||||
}
|
||||
|
||||
pub fn b(tcx: TyCtxt<'_>, lint: &'static Lint, hir_id: HirId, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
|
||||
tcx.node_span_lint(lint, hir_id, span, msg, |_| {});
|
||||
tcx.node_span_lint(lint, hir_id, span, |lint| { lint.primary_message(msg); });
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error: use of a disallowed method `rustc_lint::context::LintContext::span_lint`
|
||||
--> tests/ui-internal/disallow_span_lint.rs:14:5
|
||||
|
|
||||
LL | cx.span_lint(lint, span, msg, |_| {});
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | cx.span_lint(lint, span, |lint| { lint.primary_message(msg); });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead (from clippy.toml)
|
||||
= note: `-D clippy::disallowed-methods` implied by `-D warnings`
|
||||
|
|
@ -11,8 +11,8 @@ LL | cx.span_lint(lint, span, msg, |_| {});
|
|||
error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint`
|
||||
--> tests/ui-internal/disallow_span_lint.rs:18:5
|
||||
|
|
||||
LL | tcx.node_span_lint(lint, hir_id, span, msg, |_| {});
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | tcx.node_span_lint(lint, hir_id, span, |lint| { lint.primary_message(msg); });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead (from clippy.toml)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue