| 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(()) |
| } |