Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 31 additions & 8 deletions crates/xtask-lint-docs/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use anyhow::Context as _;
use cargo::util::command_prelude::{ArgMatchesExt, flag};
use cargo::util::lints::{Lint, LintLevel};
use itertools::Itertools;

use std::fmt::Write;
use std::path::PathBuf;

Expand All @@ -22,7 +24,7 @@ fn main() -> anyhow::Result<()> {
.iter()
.sorted_by_key(|lint| lint.name)
{
if lint.docs.is_some() {
if !lint.hidden {
let sectipn = match lint.default_level {
LintLevel::Allow => &mut allow,
LintLevel::Warn => &mut warn,
Expand Down Expand Up @@ -57,23 +59,30 @@ fn main() -> anyhow::Result<()> {

buf.push_str(&lint_docs);

let docs_output_path = lint_docs_output_path();
if check {
let old = std::fs::read_to_string(lint_docs_path())?;
let old = std::fs::read_to_string(docs_output_path)?;
if old != buf {
anyhow::bail!(
"The lints documentation is out-of-date. Run `cargo lint-docs` to update it."
);
}
} else {
std::fs::write(lint_docs_path(), buf)?;
std::fs::write(docs_output_path, buf)?;
}
Ok(())
}

fn add_lint(lint: &Lint, buf: &mut String) -> std::fmt::Result {
writeln!(buf, "## `{}`", lint.name)?;
writeln!(buf, "Set to `{}` by default", lint.default_level)?;
writeln!(buf, "{}\n", lint.docs.as_ref().unwrap())
fn add_lint(lint: &Lint, buf: &mut String) -> anyhow::Result<()> {
writeln!(buf, "## `{}`\n", lint.name)?;
writeln!(buf, "Set to `{}` by default\n", lint.default_level)?;

let src_path = lint_docs_src_path(lint);
let docs = std::fs::read_to_string(&src_path)
.with_context(|| format!("failed to read {}", src_path.display()))?;
writeln!(buf, "{docs}\n",)?;

Ok(())
}

fn add_level_section(level: LintLevel, lint_names: &[&str], buf: &mut String) -> std::fmt::Result {
Expand All @@ -97,7 +106,7 @@ fn add_level_section(level: LintLevel, lint_names: &[&str], buf: &mut String) ->
Ok(())
}

fn lint_docs_path() -> PathBuf {
fn lint_docs_output_path() -> PathBuf {
let pkg_root = env!("CARGO_MANIFEST_DIR");
let ws_root = PathBuf::from(format!("{pkg_root}/../.."));
let path = {
Expand All @@ -106,3 +115,17 @@ fn lint_docs_path() -> PathBuf {
};
path
}

/// Gets the markdown source of the lint documentation.
fn lint_docs_src_path(lint: &Lint) -> PathBuf {
let pkg_root = env!("CARGO_MANIFEST_DIR");
let ws_root = PathBuf::from(format!("{pkg_root}/../.."));
let path = {
let path = ws_root
.join("src/cargo/util/lints")
.join(lint.name)
.with_extension("md");
path.canonicalize().unwrap_or(path)
};
path
}
55 changes: 5 additions & 50 deletions src/cargo/util/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,8 @@ pub struct Lint {
pub default_level: LintLevel,
pub edition_lint_opts: Option<(Edition, LintLevel)>,
pub feature_gate: Option<&'static Feature>,
/// This is a markdown formatted string that will be used when generating
/// the lint documentation. If docs is `None`, the lint will not be
/// documented.
pub docs: Option<&'static str>,
/// Whether the lint should be hidden or documented.
pub hidden: bool,
}

impl Lint {
Expand Down Expand Up @@ -436,7 +434,7 @@ const IM_A_TEAPOT: Lint = Lint {
default_level: LintLevel::Allow,
edition_lint_opts: None,
feature_gate: Some(Feature::test_dummy_unstable()),
docs: None,
hidden: true,
};

pub fn check_im_a_teapot(
Expand Down Expand Up @@ -488,33 +486,7 @@ const BLANKET_HINT_MOSTLY_UNUSED: Lint = Lint {
default_level: LintLevel::Warn,
edition_lint_opts: None,
feature_gate: None,
docs: Some(
r#"
### What it does
Checks if `hint-mostly-unused` being applied to all dependencies.

### Why it is bad
`hint-mostly-unused` indicates that most of a crate's API surface will go
unused by anything depending on it; this hint can speed up the build by
attempting to minimize compilation time for items that aren't used at all.
Misapplication to crates that don't fit that criteria will slow down the build
rather than speeding it up. It should be selectively applied to dependencies
that meet these criteria. Applying it globally is always a misapplication and
will likely slow down the build.

### Example
```toml
[profile.dev.package."*"]
hint-mostly-unused = true
```

Should instead be:
```toml
[profile.dev.package.huge-mostly-unused-dependency]
hint-mostly-unused = true
```
"#,
),
hidden: false,
};

pub fn blanket_hint_mostly_unused(
Expand Down Expand Up @@ -640,24 +612,7 @@ const UNKNOWN_LINTS: Lint = Lint {
default_level: LintLevel::Warn,
edition_lint_opts: None,
feature_gate: None,
docs: Some(
r#"
### What it does
Checks for unknown lints in the `[lints.cargo]` table

### Why it is bad
- The lint name could be misspelled, leading to confusion as to why it is
not working as expected
- The unknown lint could end up causing an error if `cargo` decides to make
a lint with the same name in the future

### Example
```toml
[lints.cargo]
this-lint-does-not-exist = "warn"
```
"#,
),
hidden: false,
};

fn output_unknown_lints(
Expand Down
27 changes: 27 additions & 0 deletions src/cargo/util/lints/blanket_hint_mostly_unused.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
### What it does

Checks if `hint-mostly-unused` being applied to all dependencies.

### Why it is bad

`hint-mostly-unused` indicates that most of a crate's API surface will go
unused by anything depending on it; this hint can speed up the build by
attempting to minimize compilation time for items that aren't used at all.
Misapplication to crates that don't fit that criteria will slow down the build
rather than speeding it up. It should be selectively applied to dependencies
that meet these criteria. Applying it globally is always a misapplication and
will likely slow down the build.

### Example

```toml
[profile.dev.package."*"]
hint-mostly-unused = true
```

Should instead be:

```toml
[profile.dev.package.huge-mostly-unused-dependency]
hint-mostly-unused = true
```
17 changes: 17 additions & 0 deletions src/cargo/util/lints/unknown_lints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### What it does

Checks for unknown lints in the `[lints.cargo]` table

### Why it is bad

- The lint name could be misspelled, leading to confusion as to why it is
not working as expected
- The unknown lint could end up causing an error if `cargo` decides to make
a lint with the same name in the future

### Example

```toml
[lints.cargo]
this-lint-does-not-exist = "warn"
```
9 changes: 9 additions & 0 deletions src/doc/src/reference/lints.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ These lints are all set to the 'warn' level by default.
- [`unknown_lints`](#unknown_lints)

## `blanket_hint_mostly_unused`

Set to `warn` by default

### What it does

Checks if `hint-mostly-unused` being applied to all dependencies.

### Why it is bad

`hint-mostly-unused` indicates that most of a crate's API surface will go
unused by anything depending on it; this hint can speed up the build by
attempting to minimize compilation time for items that aren't used at all.
Expand All @@ -24,31 +27,37 @@ that meet these criteria. Applying it globally is always a misapplication and
will likely slow down the build.

### Example

```toml
[profile.dev.package."*"]
hint-mostly-unused = true
```

Should instead be:

```toml
[profile.dev.package.huge-mostly-unused-dependency]
hint-mostly-unused = true
```


## `unknown_lints`

Set to `warn` by default

### What it does

Checks for unknown lints in the `[lints.cargo]` table

### Why it is bad

- The lint name could be misspelled, leading to confusion as to why it is
not working as expected
- The unknown lint could end up causing an error if `cargo` decides to make
a lint with the same name in the future

### Example

```toml
[lints.cargo]
this-lint-does-not-exist = "warn"
Expand Down