From ce014be0b9d0325ad9e6ecb8c93b3c8186b18089 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 11 Sep 2020 08:55:59 -0700 Subject: [PATCH] Link rustdoc lint docs to the rustdoc book. --- compiler/rustc_session/src/lint/builtin.rs | 138 ++------------------- src/bootstrap/doc.rs | 3 - src/doc/rustdoc/src/lints.md | 58 +++++++++ src/tools/lint-docs/src/lib.rs | 36 +++--- src/tools/lint-docs/src/main.rs | 11 -- 5 files changed, 88 insertions(+), 158 deletions(-) diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 4c0c7fae29b..22030a842db 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -1817,35 +1817,10 @@ declare_lint! { declare_lint! { /// The `broken_intra_doc_links` lint detects failures in resolving - /// intra-doc link targets. This is a `rustdoc` only lint, and only works - /// on the [**nightly channel**]. + /// intra-doc link targets. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. /// - /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html - /// - /// ### Example - /// - /// ```rust,rustdoc - /// /// This is a doc comment. - /// /// - /// /// See also [`bar`]. - /// pub fn foo() { - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// `rustdoc` allows [linking to items by name][intra] which will - /// automatically generate links in the documentation to the item. This - /// lint is issued when `rustdoc` is unable to find the named item. Check - /// that the name is correct, that it is in scope, or if you need to - /// qualify it with a path. If you intended to have square brackets appear - /// literally in the text, surround the brackets with backticks such as `` - /// `[example]` `` to indicate a code span, or prefix it with a backslash - /// such as `\[example]`. - /// - /// [intra]: https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#linking-to-items-by-name + /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links pub BROKEN_INTRA_DOC_LINKS, Warn, "failures in resolving intra-doc link targets" @@ -1854,27 +1829,9 @@ declare_lint! { declare_lint! { /// The `invalid_codeblock_attributes` lint detects code block attributes /// in documentation examples that have potentially mis-typed values. This - /// is a `rustdoc` only lint. + /// is a `rustdoc` only lint, see the documentation in the [rustdoc book]. /// - /// ### Example - /// - /// ```rust,rustdoc - /// /// Example. - /// /// - /// /// ```should-panic - /// /// assert_eq!(1, 2); - /// /// ``` - /// pub fn foo() {} - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// This lint is issued when `rustdoc` detects an example code block - /// attribute that appears similar to a valid one. In the example above, - /// the correct form is `should_panic`. This helps detect typo mistakes - /// for some common attributes. + /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_codeblock_attributes pub INVALID_CODEBLOCK_ATTRIBUTES, Warn, "codeblock attribute looks a lot like a known one" @@ -1882,24 +1839,10 @@ declare_lint! { declare_lint! { /// The `missing_crate_level_docs` lint detects if documentation is - /// missing at the crate root. This is a `rustdoc` only lint. This is a - /// `rustdoc` only lint. + /// missing at the crate root. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. /// - /// ### Example - /// - /// ```rust,rustdoc - /// #![deny(missing_crate_level_docs)] - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// This lint causes `rustdoc` to check if the crate root is missing - /// documentation. This is currently "allow" by default, but it is - /// intended to make this a warning in the future. This is intended as a - /// means to introduce new users on *how* to document their crate by - /// pointing them to some instructions on how to get started. + /// [rustdoc book]: ../../../rustdoc/lints.html#missing_crate_level_docs pub MISSING_CRATE_LEVEL_DOCS, Allow, "detects crates with no crate-level documentation" @@ -1908,43 +1851,9 @@ declare_lint! { declare_lint! { /// The `missing_doc_code_examples` lint detects publicly-exported items /// without code samples in their documentation. This is a `rustdoc` only - /// lint, and only works on the [**nightly channel**]. + /// lint, see the documentation in the [rustdoc book]. /// - /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html - /// - /// ### Example - /// - /// ```rust,rustdoc - /// #![warn(missing_doc_code_examples)] - /// - /// /// There is no code example! - /// pub fn no_code_example() {} - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// This lint is to ensure a high level of quality for documentation. Code - /// examples can be very useful to see how to use an API. To add an - /// example, include a markdown code block with an example of how to use - /// the item, such as: - /// - /// ```rust - /// /// Adds one to the number given. - /// /// - /// /// # Examples - /// /// - /// /// ``` - /// /// let arg = 5; - /// /// let answer = my_crate::add_one(arg); - /// /// - /// /// assert_eq!(6, answer); - /// /// ``` - /// pub fn add_one(x: i32) -> i32 { - /// x + 1 - /// } - /// ``` + /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples pub MISSING_DOC_CODE_EXAMPLES, Allow, "detects publicly-exported items without code samples in their documentation" @@ -1952,31 +1861,10 @@ declare_lint! { declare_lint! { /// The `private_doc_tests` lint detects code samples in docs of private - /// items not documented by `rustdoc`. This is a `rustdoc` only lint. + /// items not documented by `rustdoc`. This is a `rustdoc` only lint, see + /// the documentation in the [rustdoc book]. /// - /// ### Example - /// - /// ```rust,rustdoc - /// #![deny(private_doc_tests)] - /// - /// mod foo { - /// /// private doc test - /// /// - /// /// ``` - /// /// assert!(false); - /// /// ``` - /// fn bar() {} - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Because documentation examples link against the public API of the - /// crate, it is not possible for an example to access a private item. - /// This means it was likely a mistake to add a code example to a private - /// item. + /// [rustdoc book]: ../../../rustdoc/lints.html#private_doc_tests pub PRIVATE_DOC_TESTS, Allow, "detects code samples in docs of private items not documented by rustdoc" diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index be5182b939d..98a0119e4df 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -756,7 +756,6 @@ impl Step for RustcBook { // The tool runs `rustc` for extracting output examples, so it needs a // functional sysroot. builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); - let rustdoc = builder.rustdoc(self.compiler); let mut cmd = builder.tool_cmd(Tool::LintDocs); cmd.arg("--src"); cmd.arg(builder.src.join("compiler")); @@ -764,8 +763,6 @@ impl Step for RustcBook { cmd.arg(&out_listing); cmd.arg("--rustc"); cmd.arg(rustc); - cmd.arg("--rustdoc"); - cmd.arg(rustdoc); if builder.config.verbose() { cmd.arg("--verbose"); } diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index 8e2869fef55..ce292c60460 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -49,6 +49,30 @@ warning: missing documentation for a function | ^^^^^^^^^^^^^^^^^^^^^ ``` +## missing_crate_level_docs + +This lint is **allowed by default**. It detects if there is no documentation +at the crate root. For example: + +```rust +#![warn(missing_crate_level_docs)] +``` + +This will generate the following warning: + +```text +warning: no documentation found for this crate's top-level module + | + = help: The following guide may be of use: + https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html +``` + +This is currently "allow" by default, but it is intended to make this a +warning in the future. This is intended as a means to introduce new users on +*how* to document their crate by pointing them to some instructions on how to +get started, without providing overwhelming warnings like `missing_docs` +might. + ## missing_doc_code_examples This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block @@ -117,3 +141,37 @@ warning: Documentation test in private item 8 | | /// ``` | |___________^ ``` + +## invalid_codeblock_attributes + +This lint **warns by default**. It detects code block attributes in +documentation examples that have potentially mis-typed values. For example: + +```rust +/// Example. +/// +/// ```should-panic +/// assert_eq!(1, 2); +/// ``` +pub fn foo() {} +``` + +Which will give: + +```text +warning: unknown attribute `should-panic`. Did you mean `should_panic`? + --> src/lib.rs:1:1 + | +1 | / /// Example. +2 | | /// +3 | | /// ```should-panic +4 | | /// assert_eq!(1, 2); +5 | | /// ``` + | |_______^ + | + = note: `#[warn(invalid_codeblock_attributes)]` on by default + = 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 +``` + +In the example above, the correct form is `should_panic`. This helps detect +typo mistakes for some common attributes. diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index b1e14ea6c46..a8e3278fc66 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -15,6 +15,12 @@ struct Lint { lineno: usize, } +impl Lint { + fn doc_contains(&self, text: &str) -> bool { + self.doc.iter().any(|line| line.contains(text)) + } +} + #[derive(Clone, Copy, PartialEq)] enum Level { Allow, @@ -37,12 +43,11 @@ pub fn extract_lint_docs( src_path: &Path, out_path: &Path, rustc_path: &Path, - rustdoc_path: &Path, verbose: bool, ) -> Result<(), Box> { let mut lints = gather_lints(src_path)?; for lint in &mut lints { - generate_output_example(lint, rustc_path, rustdoc_path, verbose).map_err(|e| { + generate_output_example(lint, rustc_path, verbose).map_err(|e| { format!( "failed to test example in lint docs for `{}` in {}:{}: {}", lint.name, @@ -197,7 +202,6 @@ fn lint_name(line: &str) -> Result { fn generate_output_example( lint: &mut Lint, rustc_path: &Path, - rustdoc_path: &Path, verbose: bool, ) -> Result<(), Box> { // Explicit list of lints that are allowed to not have an example. Please @@ -214,15 +218,19 @@ fn generate_output_example( ) { return Ok(()); } + if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") { + // Rustdoc lints are documented in the rustdoc book, don't check these. + return Ok(()); + } check_style(lint)?; - replace_produces(lint, rustc_path, rustdoc_path, verbose)?; + replace_produces(lint, rustc_path, verbose)?; Ok(()) } /// Checks the doc style of the lint. fn check_style(lint: &Lint) -> Result<(), Box> { for expected in &["### Example", "### Explanation", "{{produces}}"] { - if !lint.doc.iter().any(|line| line.contains(expected)) { + if !lint.doc_contains(expected) { return Err(format!("lint docs should contain the line `{}`", expected).into()); } } @@ -243,7 +251,6 @@ fn check_style(lint: &Lint) -> Result<(), Box> { fn replace_produces( lint: &mut Lint, rustc_path: &Path, - rustdoc_path: &Path, verbose: bool, ) -> Result<(), Box> { let mut lines = lint.doc.iter_mut(); @@ -283,14 +290,8 @@ fn replace_produces( match lines.next() { Some(line) if line.is_empty() => {} Some(line) if line == "{{produces}}" => { - let output = generate_lint_output( - &lint.name, - &example, - &options, - rustc_path, - rustdoc_path, - verbose, - )?; + let output = + generate_lint_output(&lint.name, &example, &options, rustc_path, verbose)?; line.replace_range( .., &format!( @@ -318,7 +319,6 @@ fn generate_lint_output( example: &[&mut String], options: &[&str], rustc_path: &Path, - rustdoc_path: &Path, verbose: bool, ) -> Result> { if verbose { @@ -327,8 +327,7 @@ fn generate_lint_output( let tempdir = tempfile::TempDir::new()?; let tempfile = tempdir.path().join("lint_example.rs"); let mut source = String::new(); - let is_rustdoc = options.contains(&"rustdoc"); - let needs_main = !example.iter().any(|line| line.contains("fn main")) && !is_rustdoc; + let needs_main = !example.iter().any(|line| line.contains("fn main")); // Remove `# ` prefix for hidden lines. let unhidden = example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line }); @@ -354,8 +353,7 @@ fn generate_lint_output( } fs::write(&tempfile, source) .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; - let program = if is_rustdoc { rustdoc_path } else { rustc_path }; - let mut cmd = Command::new(program); + let mut cmd = Command::new(rustc_path); if options.contains(&"edition2015") { cmd.arg("--edition=2015"); } else { diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs index 4b824596b46..45d97bd4317 100644 --- a/src/tools/lint-docs/src/main.rs +++ b/src/tools/lint-docs/src/main.rs @@ -13,7 +13,6 @@ fn doit() -> Result<(), Box> { let mut src_path = None; let mut out_path = None; let mut rustc_path = None; - let mut rustdoc_path = None; let mut verbose = false; while let Some(arg) = args.next() { match arg.as_str() { @@ -35,12 +34,6 @@ fn doit() -> Result<(), Box> { None => return Err("--rustc requires a value".into()), }; } - "--rustdoc" => { - rustdoc_path = match args.next() { - Some(s) => Some(PathBuf::from(s)), - None => return Err("--rustdoc requires a value".into()), - }; - } "-v" | "--verbose" => verbose = true, s => return Err(format!("unexpected argument `{}`", s).into()), } @@ -54,14 +47,10 @@ fn doit() -> Result<(), Box> { if rustc_path.is_none() { return Err("--rustc must be specified to the path of rustc".into()); } - if rustdoc_path.is_none() { - return Err("--rustdoc must be specified to the path of rustdoc".into()); - } lint_docs::extract_lint_docs( &src_path.unwrap(), &out_path.unwrap(), &rustc_path.unwrap(), - &rustdoc_path.unwrap(), verbose, ) }