diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index abc27bcdf0782..dfad1ab10dbe0 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -27,7 +27,7 @@ //! ``` use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; +use rustc_errors::{DiagnosticBuilder, DiagnosticMessage}; use rustc_hir::def_id::DefId; use rustc_middle::ty::TyCtxt; pub(crate) use rustc_resolve::rustdoc::main_body_opts; @@ -234,10 +234,6 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { fn next(&mut self) -> Option { let event = self.inner.next(); - let compile_fail; - let should_panic; - let ignore; - let edition; let Some(Event::Start(Tag::CodeBlock(kind))) = event else { return event; }; @@ -253,49 +249,44 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { } } - let parse_result = match kind { - CodeBlockKind::Fenced(ref lang) => { - let parse_result = LangString::parse_without_check( - lang, - self.check_error_codes, - false, - self.custom_code_classes_in_docs, - ); - if !parse_result.rust { - let added_classes = parse_result.added_classes; - let lang_string = if let Some(lang) = parse_result.unknown.first() { - format!("language-{}", lang) - } else { - String::new() - }; - let whitespace = if added_classes.is_empty() { "" } else { " " }; - return Some(Event::Html( - format!( - "
\ + let LangString { added_classes, compile_fail, should_panic, ignore, edition, .. } = + match kind { + CodeBlockKind::Fenced(ref lang) => { + let parse_result = LangString::parse_without_check( + lang, + self.check_error_codes, + false, + self.custom_code_classes_in_docs, + ); + if !parse_result.rust { + let added_classes = parse_result.added_classes; + let lang_string = if let Some(lang) = parse_result.unknown.first() { + format!("language-{}", lang) + } else { + String::new() + }; + let whitespace = if added_classes.is_empty() { "" } else { " " }; + return Some(Event::Html( + format!( + "
\
\
                                      {text}\
                                  
\
", - added_classes = added_classes.join(" "), - text = Escape(&original_text), - ) - .into(), - )); + added_classes = added_classes.join(" "), + text = Escape(&original_text), + ) + .into(), + )); + } + parse_result } - parse_result - } - CodeBlockKind::Indented => Default::default(), - }; + CodeBlockKind::Indented => Default::default(), + }; - let added_classes = parse_result.added_classes; let lines = original_text.lines().filter_map(|l| map_line(l).for_html()); let text = lines.intersperse("\n".into()).collect::(); - compile_fail = parse_result.compile_fail; - should_panic = parse_result.should_panic; - ignore = parse_result.ignore; - edition = parse_result.edition; - let explicit_edition = edition.is_some(); let edition = edition.unwrap_or(self.edition); @@ -852,7 +843,9 @@ impl<'tcx> ExtraInfo<'tcx> { fn error_invalid_codeblock_attr_with_help( &self, msg: impl Into, - help: impl Into, + f: impl for<'a, 'b> FnOnce( + &'b mut DiagnosticBuilder<'a, ()>, + ) -> &'b mut DiagnosticBuilder<'a, ()>, ) { if let Some(def_id) = self.def_id.as_local() { self.tcx.struct_span_lint_hir( @@ -860,7 +853,7 @@ impl<'tcx> ExtraInfo<'tcx> { self.tcx.local_def_id_to_hir_id(def_id), self.sp, msg, - |lint| lint.help(help), + f, ); } } @@ -1293,6 +1286,21 @@ impl LangString { LangStringToken::LangToken(x) if x.starts_with("edition") => { data.edition = x[7..].parse::().ok(); } + LangStringToken::LangToken(x) + if x.starts_with("rust") && x[4..].parse::().is_ok() => + { + if let Some(extra) = extra { + extra.error_invalid_codeblock_attr_with_help( + format!("unknown attribute `{x}`"), + |lint| { + lint.help(format!( + "there is an attribute with a similar name: `edition{}`", + &x[4..], + )) + }, + ); + } + } LangStringToken::LangToken(x) if allow_error_code_check && x.starts_with('E') && x.len() == 5 => { @@ -1337,8 +1345,13 @@ impl LangString { } { if let Some(extra) = extra { extra.error_invalid_codeblock_attr_with_help( - format!("unknown attribute `{x}`. Did you mean `{flag}`?"), - help, + format!("unknown attribute `{x}`"), + |lint| { + lint.help(format!( + "there is an attribute with a similar name: `{flag}`" + )) + .help(help) + }, ); } } diff --git a/tests/rustdoc-ui/doctest/check-attr-test.stderr b/tests/rustdoc-ui/doctest/check-attr-test.stderr index 01beba1ffc4a4..10f763a6f9d86 100644 --- a/tests/rustdoc-ui/doctest/check-attr-test.stderr +++ b/tests/rustdoc-ui/doctest/check-attr-test.stderr @@ -1,4 +1,4 @@ -error: unknown attribute `compile-fail`. Did you mean `compile_fail`? +error: unknown attribute `compile-fail` --> $DIR/check-attr-test.rs:5:1 | 5 | / /// foo @@ -8,6 +8,7 @@ error: unknown attribute `compile-fail`. Did you mean `compile_fail`? 9 | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `compile_fail` = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully note: the lint level is defined here --> $DIR/check-attr-test.rs:3:9 @@ -15,7 +16,7 @@ note: the lint level is defined here 3 | #![deny(rustdoc::invalid_codeblock_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: unknown attribute `compilefail`. Did you mean `compile_fail`? +error: unknown attribute `compilefail` --> $DIR/check-attr-test.rs:5:1 | 5 | / /// foo @@ -25,9 +26,10 @@ error: unknown attribute `compilefail`. Did you mean `compile_fail`? 9 | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `compile_fail` = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully -error: unknown attribute `comPile_fail`. Did you mean `compile_fail`? +error: unknown attribute `comPile_fail` --> $DIR/check-attr-test.rs:5:1 | 5 | / /// foo @@ -37,9 +39,10 @@ error: unknown attribute `comPile_fail`. Did you mean `compile_fail`? 9 | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `compile_fail` = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully -error: unknown attribute `should-panic`. Did you mean `should_panic`? +error: unknown attribute `should-panic` --> $DIR/check-attr-test.rs:12:1 | 12 | / /// bar @@ -49,9 +52,10 @@ error: unknown attribute `should-panic`. Did you mean `should_panic`? 16 | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `should_panic` = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running -error: unknown attribute `shouldpanic`. Did you mean `should_panic`? +error: unknown attribute `shouldpanic` --> $DIR/check-attr-test.rs:12:1 | 12 | / /// bar @@ -61,9 +65,10 @@ error: unknown attribute `shouldpanic`. Did you mean `should_panic`? 16 | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `should_panic` = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running -error: unknown attribute `shOuld_panic`. Did you mean `should_panic`? +error: unknown attribute `shOuld_panic` --> $DIR/check-attr-test.rs:12:1 | 12 | / /// bar @@ -73,9 +78,10 @@ error: unknown attribute `shOuld_panic`. Did you mean `should_panic`? 16 | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `should_panic` = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running -error: unknown attribute `no-run`. Did you mean `no_run`? +error: unknown attribute `no-run` --> $DIR/check-attr-test.rs:19:1 | 19 | / /// foobar @@ -85,9 +91,10 @@ error: unknown attribute `no-run`. Did you mean `no_run`? 23 | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `no_run` = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) -error: unknown attribute `norun`. Did you mean `no_run`? +error: unknown attribute `norun` --> $DIR/check-attr-test.rs:19:1 | 19 | / /// foobar @@ -97,9 +104,10 @@ error: unknown attribute `norun`. Did you mean `no_run`? 23 | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `no_run` = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) -error: unknown attribute `nO_run`. Did you mean `no_run`? +error: unknown attribute `nO_run` --> $DIR/check-attr-test.rs:19:1 | 19 | / /// foobar @@ -109,9 +117,10 @@ error: unknown attribute `nO_run`. Did you mean `no_run`? 23 | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `no_run` = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) -error: unknown attribute `test-harness`. Did you mean `test_harness`? +error: unknown attribute `test-harness` --> $DIR/check-attr-test.rs:26:1 | 26 | / /// b @@ -121,9 +130,10 @@ error: unknown attribute `test-harness`. Did you mean `test_harness`? 30 | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `test_harness` = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function -error: unknown attribute `testharness`. Did you mean `test_harness`? +error: unknown attribute `testharness` --> $DIR/check-attr-test.rs:26:1 | 26 | / /// b @@ -133,9 +143,10 @@ error: unknown attribute `testharness`. Did you mean `test_harness`? 30 | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `test_harness` = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function -error: unknown attribute `tesT_harness`. Did you mean `test_harness`? +error: unknown attribute `tesT_harness` --> $DIR/check-attr-test.rs:26:1 | 26 | / /// b @@ -145,6 +156,7 @@ error: unknown attribute `tesT_harness`. Did you mean `test_harness`? 30 | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `test_harness` = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function error: aborting due to 12 previous errors diff --git a/tests/rustdoc-ui/lints/check-attr.rs b/tests/rustdoc-ui/lints/check-attr.rs index 0b3f7bedda5cf..3c06e6c076bf6 100644 --- a/tests/rustdoc-ui/lints/check-attr.rs +++ b/tests/rustdoc-ui/lints/check-attr.rs @@ -39,3 +39,20 @@ pub fn foobar() {} /// boo /// ``` pub fn b() {} + +/// b +//~^ ERROR +/// +/// ```rust2018 +/// boo +/// ``` +pub fn c() {} + +/// b +//~^ ERROR +//~| ERROR +/// +/// ```rust2018 shouldpanic +/// boo +/// ``` +pub fn d() {} diff --git a/tests/rustdoc-ui/lints/check-attr.stderr b/tests/rustdoc-ui/lints/check-attr.stderr index f66e63ab727ea..d640125ab5133 100644 --- a/tests/rustdoc-ui/lints/check-attr.stderr +++ b/tests/rustdoc-ui/lints/check-attr.stderr @@ -1,4 +1,4 @@ -error: unknown attribute `compile-fail`. Did you mean `compile_fail`? +error: unknown attribute `compile-fail` --> $DIR/check-attr.rs:3:1 | LL | / /// foo @@ -10,6 +10,7 @@ LL | | /// boo LL | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `compile_fail` = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully note: the lint level is defined here --> $DIR/check-attr.rs:1:9 @@ -17,7 +18,7 @@ note: the lint level is defined here LL | #![deny(rustdoc::invalid_codeblock_attributes)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: unknown attribute `compilefail`. Did you mean `compile_fail`? +error: unknown attribute `compilefail` --> $DIR/check-attr.rs:3:1 | LL | / /// foo @@ -29,9 +30,10 @@ LL | | /// boo LL | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `compile_fail` = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully -error: unknown attribute `comPile_fail`. Did you mean `compile_fail`? +error: unknown attribute `comPile_fail` --> $DIR/check-attr.rs:3:1 | LL | / /// foo @@ -43,9 +45,10 @@ LL | | /// boo LL | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `compile_fail` = help: the code block will either not be tested if not marked as a rust one or won't fail if it compiles successfully -error: unknown attribute `should-panic`. Did you mean `should_panic`? +error: unknown attribute `should-panic` --> $DIR/check-attr.rs:13:1 | LL | / /// bar @@ -57,9 +60,10 @@ LL | | /// boo LL | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `should_panic` = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running -error: unknown attribute `shouldpanic`. Did you mean `should_panic`? +error: unknown attribute `shouldpanic` --> $DIR/check-attr.rs:13:1 | LL | / /// bar @@ -71,9 +75,10 @@ LL | | /// boo LL | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `should_panic` = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running -error: unknown attribute `sHould_panic`. Did you mean `should_panic`? +error: unknown attribute `sHould_panic` --> $DIR/check-attr.rs:13:1 | LL | / /// bar @@ -85,9 +90,10 @@ LL | | /// boo LL | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `should_panic` = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running -error: unknown attribute `no-run`. Did you mean `no_run`? +error: unknown attribute `no-run` --> $DIR/check-attr.rs:23:1 | LL | / /// foobar @@ -99,9 +105,10 @@ LL | | /// boo LL | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `no_run` = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) -error: unknown attribute `norun`. Did you mean `no_run`? +error: unknown attribute `norun` --> $DIR/check-attr.rs:23:1 | LL | / /// foobar @@ -113,9 +120,10 @@ LL | | /// boo LL | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `no_run` = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) -error: unknown attribute `no_Run`. Did you mean `no_run`? +error: unknown attribute `no_Run` --> $DIR/check-attr.rs:23:1 | LL | / /// foobar @@ -127,9 +135,10 @@ LL | | /// boo LL | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `no_run` = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want) -error: unknown attribute `test-harness`. Did you mean `test_harness`? +error: unknown attribute `test-harness` --> $DIR/check-attr.rs:33:1 | LL | / /// b @@ -141,9 +150,10 @@ LL | | /// boo LL | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `test_harness` = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function -error: unknown attribute `testharness`. Did you mean `test_harness`? +error: unknown attribute `testharness` --> $DIR/check-attr.rs:33:1 | LL | / /// b @@ -155,9 +165,10 @@ LL | | /// boo LL | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `test_harness` = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function -error: unknown attribute `teSt_harness`. Did you mean `test_harness`? +error: unknown attribute `teSt_harness` --> $DIR/check-attr.rs:33:1 | LL | / /// b @@ -169,7 +180,50 @@ LL | | /// boo LL | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `test_harness` = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function -error: aborting due to 12 previous errors +error: unknown attribute `rust2018` + --> $DIR/check-attr.rs:43:1 + | +LL | / /// b +LL | | +LL | | /// +LL | | /// ```rust2018 +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: there is an attribute with a similar name: `edition2018` + +error: unknown attribute `rust2018` + --> $DIR/check-attr.rs:51:1 + | +LL | / /// b +LL | | +LL | | +LL | | /// +LL | | /// ```rust2018 shouldpanic +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: there is an attribute with a similar name: `edition2018` + +error: unknown attribute `shouldpanic` + --> $DIR/check-attr.rs:51:1 + | +LL | / /// b +LL | | +LL | | +LL | | /// +LL | | /// ```rust2018 shouldpanic +LL | | /// boo +LL | | /// ``` + | |_______^ + | + = help: there is an attribute with a similar name: `should_panic` + = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running + +error: aborting due to 15 previous errors diff --git a/tests/rustdoc-ui/lints/check-fail.stderr b/tests/rustdoc-ui/lints/check-fail.stderr index f05e457af6452..99b01bac59882 100644 --- a/tests/rustdoc-ui/lints/check-fail.stderr +++ b/tests/rustdoc-ui/lints/check-fail.stderr @@ -22,7 +22,7 @@ note: the lint level is defined here LL | #![deny(rustdoc::missing_doc_code_examples)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: unknown attribute `testharness`. Did you mean `test_harness`? +error: unknown attribute `testharness` --> $DIR/check-fail.rs:8:1 | LL | / //! ```rust,testharness @@ -31,6 +31,7 @@ LL | | //! let x = 12; LL | | //! ``` | |_______^ | + = help: there is an attribute with a similar name: `test_harness` = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function note: the lint level is defined here --> $DIR/check-fail.rs:6:9 @@ -39,7 +40,7 @@ LL | #![deny(rustdoc::all)] | ^^^^^^^^^^^^ = note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(rustdoc::all)]` -error: unknown attribute `testharness`. Did you mean `test_harness`? +error: unknown attribute `testharness` --> $DIR/check-fail.rs:17:1 | LL | / /// hello @@ -50,6 +51,7 @@ LL | | /// let x = 12; LL | | /// ``` | |_______^ | + = help: there is an attribute with a similar name: `test_harness` = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function error: aborting due to 4 previous errors