blob: 926684fb5bdc28473e52923eeb2823237354f44c [file] [edit]
use std::path::Path;
use cargo_util_terminal::report::Group;
use cargo_util_terminal::report::Level;
use cargo_util_terminal::report::Origin;
use cargo_util_terminal::report::Patch;
use cargo_util_terminal::report::Snippet;
use tracing::instrument;
use super::SUSPICIOUS;
use crate::CargoResult;
use crate::GlobalContext;
use crate::diagnostics::Lint;
use crate::diagnostics::LintLevelProduct;
use crate::diagnostics::ScopedDiagnosticStats;
use crate::diagnostics::workspace_rel_path;
use crate::workspace::Package;
use crate::workspace::Workspace;
pub static LINT: &Lint = &Lint {
name: "missing_lints_inheritance",
desc: "missing `[lints]` to inherit `[workspace.lints]`",
primary_group: &SUSPICIOUS,
msrv: Some(super::CARGO_LINTS_MSRV),
feature_gate: None,
docs: Some(
r#"
### What it does
Checks for packages without a `lints` table while `workspace.lints` is present.
### Why is this bad?
Many people mistakenly think that `workspace.lints` is implicitly inherited when it is not.
### Drawbacks
### Example
```toml
[workspace.lints.cargo]
```
Should be written as:
```toml
[workspace.lints.cargo]
[lints]
workspace = true
```
or make it explicit that you don't intend to inherit by adding an empty `[lints]` table:
```toml
[workspace.lints.cargo]
[lints]
```
"#,
),
};
#[instrument(skip_all)]
pub(crate) fn lint_package(
ws: &Workspace<'_>,
pkg: &Package,
manifest_path: &Path,
level: LintLevelProduct,
pkg_stats: &mut ScopedDiagnosticStats<'_>,
gctx: &GlobalContext,
) -> CargoResult<()> {
let LintLevelProduct {
level: lint_level,
source,
} = level;
let root = ws.root_maybe();
// `normalized_toml` normally isn't guaranteed to include inheritance information except
// `workspace.lints` is used outside of inheritance for workspace-level lints.
let ws_lints = root
.normalized_toml()
.workspace
.as_ref()
.map(|ws| ws.lints.is_some())
.unwrap_or(false);
if !ws_lints {
return Ok(());
}
if pkg.manifest().normalized_toml().lints.is_some() {
return Ok(());
}
let manifest = pkg.manifest();
let contents = manifest.contents();
let level = lint_level.to_diagnostic_level();
let emitted_source = LINT.emitted_source(lint_level, source);
let manifest_path = workspace_rel_path(ws, manifest_path);
let mut primary = Group::with_title(level.primary_title(LINT.desc));
primary = primary.element(Origin::path(&manifest_path));
primary = primary.element(Level::NOTE.message(emitted_source));
let mut report = vec![primary];
if let Some(contents) = contents {
let span = contents.len()..contents.len();
let mut help =
Group::with_title(Level::HELP.secondary_title("to inherit `workspace.lints, add:"));
help = help.element(
Snippet::source(contents)
.path(&manifest_path)
.patch(Patch::new(span.clone(), "\n[lints]\nworkspace = true")),
);
report.push(help);
let mut help = Group::with_title(
Level::HELP.secondary_title("to clarify your intent to not inherit, add:"),
);
help = help.element(
Snippet::source(contents)
.path(&manifest_path)
.patch(Patch::new(span, "\n[lints]")),
);
report.push(help);
}
pkg_stats.record_lint(lint_level);
gctx.shell().print_report(&report, lint_level.force())?;
Ok(())
}