From c6cba68c16e2dd9e2d05f3c941d58fdbebd0d1a0 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 28 Feb 2023 18:21:49 -0800 Subject: [PATCH 1/3] Add check for errant {{produces}} marker. If a lint example has an `ignore` tag, but the lint author also includes the {{produces}} marker, then the output will just contain the text `{{produces}}`. This adds a check for this mistake and provides help on how the lint docs should be written. --- src/tools/lint-docs/src/lib.rs | 38 ++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 3842a649c6f96..e120661b96ccb 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -45,6 +45,36 @@ impl Lint { fn check_style(&self) -> Result<(), Box> { for &expected in &["### Example", "### Explanation", "{{produces}}"] { if expected == "{{produces}}" && self.is_ignored() { + if self.doc_contains("{{produces}}") { + return Err(format!( + "the lint example has `ignore`, but also contains the {{{{produces}}}} marker\n\ + \n\ + The documentation generator cannot generate the example output when the \ + example is ignored.\n\ + Manually include the sample output below the example. For example:\n\ + \n\ + /// ```rust,ignore (needs command line option)\n\ + /// #[cfg(widnows)]\n\ + /// fn foo() {{}}\n\ + /// ```\n\ + ///\n\ + /// This will produce:\n\ + /// \n\ + /// ```text\n\ + /// warning: unknown condition name used\n\ + /// --> lint_example.rs:1:7\n\ + /// |\n\ + /// 1 | #[cfg(widnows)]\n\ + /// | ^^^^^^^\n\ + /// |\n\ + /// = note: `#[warn(unexpected_cfgs)]` on by default\n\ + /// ```\n\ + \n\ + Replacing the output with the text of the example you \ + compiled manually yourself.\n\ + " + ).into()); + } continue; } if !self.doc_contains(expected) { @@ -317,10 +347,10 @@ impl<'a> LintExtractor<'a> { .., &format!( "This will produce:\n\ - \n\ - ```text\n\ - {}\ - ```", + \n\ + ```text\n\ + {}\ + ```", output ), ); From 15450b1b213d568c83bf1ba71618ddba6979e1d7 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 28 Feb 2023 18:22:05 -0800 Subject: [PATCH 2/3] Fix the ffi_unwind_calls lint documentation --- compiler/rustc_lint_defs/src/builtin.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 46ec1a2dca1f7..9090ecac9e3f4 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3967,14 +3967,9 @@ declare_lint! { /// /// ### Example /// - /// ```rust,ignore (need FFI) - /// #![feature(ffi_unwind_calls)] + /// ```rust /// #![feature(c_unwind)] - /// - /// # mod impl { - /// # #[no_mangle] - /// # pub fn "C-unwind" fn foo() {} - /// # } + /// #![warn(ffi_unwind_calls)] /// /// extern "C-unwind" { /// fn foo(); From ab2508a71f5743717a62744ee26cee11ba4d2f91 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 28 Feb 2023 18:46:54 -0800 Subject: [PATCH 3/3] Collect all matching messages for a lint. Some examples may contain multiple lines which trigger the lint. Previously it would only display the first message. This updates it so that all matching instances of the lint are displayed. --- src/tools/lint-docs/src/lib.rs | 57 +++++++++++++++++----------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index e120661b96ccb..034c6aa0708ec 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -422,37 +422,36 @@ impl<'a> LintExtractor<'a> { .filter(|line| line.starts_with('{')) .map(serde_json::from_str) .collect::, _>>()?; - match msgs + // First try to find the messages with the `code` field set to our lint. + let matches: Vec<_> = msgs .iter() - .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name)) - { - Some(msg) => { - let rendered = msg["rendered"].as_str().expect("rendered field should exist"); - Ok(rendered.to_string()) - } - None => { - match msgs.iter().find( - |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)), - ) { - Some(msg) => { - let rendered = msg["rendered"].as_str().expect("rendered field should exist"); - Ok(rendered.to_string()) - } - None => { - let rendered: Vec<&str> = - msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); - let non_json: Vec<&str> = - stderr.lines().filter(|line| !line.starts_with('{')).collect(); - Err(format!( - "did not find lint `{}` in output of example, got:\n{}\n{}", - name, - non_json.join("\n"), - rendered.join("\n") - ) - .into()) - } - } + .filter(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name)) + .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string()) + .collect(); + if matches.is_empty() { + // Some lints override their code to something else (E0566). + // Try to find something that looks like it could be our lint. + let matches: Vec<_> = msgs.iter().filter(|msg| + matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name))) + .map(|msg| msg["rendered"].as_str().expect("rendered field should exist").to_string()) + .collect(); + if matches.is_empty() { + let rendered: Vec<&str> = + msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); + let non_json: Vec<&str> = + stderr.lines().filter(|line| !line.starts_with('{')).collect(); + Err(format!( + "did not find lint `{}` in output of example, got:\n{}\n{}", + name, + non_json.join("\n"), + rendered.join("\n") + ) + .into()) + } else { + Ok(matches.join("\n")) } + } else { + Ok(matches.join("\n")) } }