Skip to content
Merged
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
98 changes: 33 additions & 65 deletions src/cargo/core/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::core::{
PatchLocation,
};
use crate::core::{EitherManifest, Package, SourceId, VirtualManifest};
use crate::diagnostics::DiagnosticStats;
use crate::diagnostics::rules::blanket_hint_mostly_unused;
use crate::diagnostics::rules::check_im_a_teapot;
use crate::diagnostics::rules::implicit_minimum_version_req_pkg;
Expand Down Expand Up @@ -1350,93 +1351,67 @@ impl<'gctx> Workspace<'gctx> {
.unwrap_or(manifest::TomlToolLints::default());

if self.gctx.cli_unstable().cargo_lints {
let mut verify_error_count = 0;
let mut verify_stats = DiagnosticStats::new();

missing_lints_features(
pkg.into(),
&path,
&cargo_lints,
&mut verify_error_count,
&mut verify_stats,
self.gctx,
)?;
unknown_lints(
pkg.into(),
&path,
&cargo_lints,
&mut verify_error_count,
&mut verify_stats,
self.gctx,
)?;

if verify_error_count > 0 {
let plural = if verify_error_count == 1 { "" } else { "s" };
bail!("encountered {verify_error_count} error{plural} while verifying lints")
}
verify_stats.report_summary("parse", Some(&*pkg.name()), self.gctx)?;

let mut run_error_count = 0;
let mut run_stats = DiagnosticStats::new();

check_im_a_teapot(pkg, &path, &cargo_lints, &mut run_error_count, self.gctx)?;
implicit_minimum_version_req_pkg(
pkg,
&path,
&cargo_lints,
&mut run_error_count,
self.gctx,
)?;
non_kebab_case_packages(pkg, &path, &cargo_lints, &mut run_error_count, self.gctx)?;
non_snake_case_packages(pkg, &path, &cargo_lints, &mut run_error_count, self.gctx)?;
non_kebab_case_bins(
self,
pkg,
&path,
&cargo_lints,
&mut run_error_count,
self.gctx,
)?;
non_kebab_case_features(pkg, &path, &cargo_lints, &mut run_error_count, self.gctx)?;
non_snake_case_features(pkg, &path, &cargo_lints, &mut run_error_count, self.gctx)?;
check_im_a_teapot(pkg, &path, &cargo_lints, &mut run_stats, self.gctx)?;
implicit_minimum_version_req_pkg(pkg, &path, &cargo_lints, &mut run_stats, self.gctx)?;
non_kebab_case_packages(pkg, &path, &cargo_lints, &mut run_stats, self.gctx)?;
non_snake_case_packages(pkg, &path, &cargo_lints, &mut run_stats, self.gctx)?;
non_kebab_case_bins(self, pkg, &path, &cargo_lints, &mut run_stats, self.gctx)?;
non_kebab_case_features(pkg, &path, &cargo_lints, &mut run_stats, self.gctx)?;
non_snake_case_features(pkg, &path, &cargo_lints, &mut run_stats, self.gctx)?;
unused_build_dependencies_no_build_rs(
pkg,
&path,
&cargo_lints,
&mut run_error_count,
self.gctx,
)?;
redundant_readme(pkg, &path, &cargo_lints, &mut run_error_count, self.gctx)?;
redundant_homepage(pkg, &path, &cargo_lints, &mut run_error_count, self.gctx)?;
missing_lints_inheritance(
self,
pkg,
&path,
&cargo_lints,
&mut run_error_count,
&mut run_stats,
self.gctx,
)?;
redundant_readme(pkg, &path, &cargo_lints, &mut run_stats, self.gctx)?;
redundant_homepage(pkg, &path, &cargo_lints, &mut run_stats, self.gctx)?;
missing_lints_inheritance(self, pkg, &path, &cargo_lints, &mut run_stats, self.gctx)?;
text_direction_codepoint_in_comment(
pkg.into(),
&path,
&cargo_lints,
&mut run_error_count,
&mut run_stats,
self.gctx,
)?;
text_direction_codepoint_in_literal(
pkg.into(),
&path,
&cargo_lints,
&mut run_error_count,
&mut run_stats,
self.gctx,
)?;

if run_error_count > 0 {
let plural = if run_error_count == 1 { "" } else { "s" };
bail!("encountered {run_error_count} error{plural} while running lints")
}
run_stats.report_summary("parse", Some(&*pkg.name()), self.gctx)?;
}

Ok(())
}

pub fn emit_ws_lints(&self) -> CargoResult<()> {
let mut run_error_count = 0;
let mut run_stats = DiagnosticStats::new();

let cargo_lints = match self.root_maybe() {
MaybePackage::Package(pkg) => {
Expand All @@ -1460,64 +1435,61 @@ impl<'gctx> Workspace<'gctx> {
.unwrap_or(manifest::TomlToolLints::default());

if self.gctx.cli_unstable().cargo_lints {
let mut verify_error_count = 0;
let mut verify_stats = DiagnosticStats::new();

missing_lints_features(
(self, self.root_maybe()).into(),
self.root_manifest(),
&cargo_lints,
&mut verify_error_count,
&mut verify_stats,
self.gctx,
)?;
unknown_lints(
(self, self.root_maybe()).into(),
self.root_manifest(),
&cargo_lints,
&mut verify_error_count,
&mut verify_stats,
self.gctx,
)?;

if verify_error_count > 0 {
let plural = if verify_error_count == 1 { "" } else { "s" };
bail!("encountered {verify_error_count} error{plural} while verifying lints")
}
verify_stats.report_summary("parse", None, self.gctx)?;

unused_workspace_package_fields(
self,
self.root_maybe(),
self.root_manifest(),
&cargo_lints,
&mut run_error_count,
&mut run_stats,
self.gctx,
)?;
unused_workspace_dependencies(
self,
self.root_maybe(),
self.root_manifest(),
&cargo_lints,
&mut run_error_count,
&mut run_stats,
self.gctx,
)?;
implicit_minimum_version_req_ws(
self,
self.root_maybe(),
self.root_manifest(),
&cargo_lints,
&mut run_error_count,
&mut run_stats,
self.gctx,
)?;
text_direction_codepoint_in_comment(
(self, self.root_maybe()).into(),
self.root_manifest(),
&cargo_lints,
&mut run_error_count,
&mut run_stats,
self.gctx,
)?;
text_direction_codepoint_in_literal(
(self, self.root_maybe()).into(),
self.root_manifest(),
&cargo_lints,
&mut run_error_count,
&mut run_stats,
self.gctx,
)?;
}
Expand All @@ -1531,17 +1503,13 @@ impl<'gctx> Workspace<'gctx> {
self.root_maybe(),
self.root_manifest(),
&cargo_lints,
&mut run_error_count,
&mut run_stats,
self.gctx,
)?;
}

if run_error_count > 0 {
let plural = if run_error_count == 1 { "" } else { "s" };
bail!("encountered {run_error_count} error{plural} while running lints")
} else {
Ok(())
}
run_stats.report_summary("parse", None, self.gctx)?;
Ok(())
}

pub fn set_target_dir(&mut self, target_dir: Filesystem) {
Expand Down
68 changes: 68 additions & 0 deletions src/cargo/diagnostics/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use anyhow::bail;
use cargo_util_schemas::manifest::RustVersion;
use cargo_util_schemas::manifest::TomlToolLints;

use crate::CargoResult;
use crate::core::Workspace;
use crate::core::{Edition, Features, MaybePackage, Package};
use crate::util::GlobalContext;

mod lint;
mod report;
Expand All @@ -13,6 +16,71 @@ pub use lint::{Lint, LintGroup, LintLevel, LintLevelSource};
pub use report::{AsIndex, get_key_value, get_key_value_span, rel_cwd_manifest_path};
pub use rules::{LINT_GROUPS, LINTS};

pub struct DiagnosticStats {
warning_count: usize,
error_count: usize,
}

impl DiagnosticStats {
pub fn new() -> Self {
Self {
warning_count: 0,
error_count: 0,
}
}

pub fn record_warning(&mut self) {
self.warning_count += 1;
}

pub fn record_error(&mut self) {
self.error_count += 1;
}

pub fn record_lint(&mut self, lint: LintLevel) {
match lint {
LintLevel::Forbid | LintLevel::Deny => {
self.record_error();
}
LintLevel::Warn => {
self.record_warning();
}
LintLevel::Allow => {}
}
}

pub fn report_summary(
&self,
action: &str,
name: Option<&str>,
gctx: &GlobalContext,
) -> CargoResult<()> {
if 0 < self.warning_count {
let plural = if self.warning_count == 1 { "" } else { "s" };
let name = name
.map(|n| format!("`{n}`"))
.unwrap_or_else(|| "workspace".to_owned());
gctx.shell().warn(format!(
"{name} (manifest) generated {} warning{plural}",
self.warning_count
))?;
}

if 0 < self.error_count {
let plural = if self.error_count == 1 { "" } else { "s" };
let name = name
.map(|n| format!("`{n}`"))
.unwrap_or_else(|| "workspace".to_owned());
bail!(
"could not {action} {name} (manifest) due to {} previous error{plural}",
self.error_count
)
}

Ok(())
}
}

/// Scope at which a lint runs: package-level or workspace-level.
pub enum ManifestFor<'a> {
/// Lint runs for a specific package.
Expand Down
7 changes: 3 additions & 4 deletions src/cargo/diagnostics/rules/blanket_hint_mostly_unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::CargoResult;
use crate::GlobalContext;
use crate::core::MaybePackage;
use crate::core::Workspace;
use crate::diagnostics::DiagnosticStats;
use crate::diagnostics::Lint;
use crate::diagnostics::LintLevel;
use crate::diagnostics::get_key_value_span;
Expand Down Expand Up @@ -61,7 +62,7 @@ pub fn blanket_hint_mostly_unused(
maybe_pkg: &MaybePackage,
path: &Path,
pkg_lints: &TomlToolLints,
error_count: &mut usize,
stats: &mut DiagnosticStats,
gctx: &GlobalContext,
) -> CargoResult<()> {
let (lint_level, source) = LINT.level(
Expand Down Expand Up @@ -120,9 +121,6 @@ pub fn blanket_hint_mostly_unused(
}

for (i, (path, show_per_pkg_suggestion)) in paths.iter().enumerate() {
if lint_level.is_error() {
*error_count += 1;
}
let title = "`hint-mostly-unused` is being blanket applied to all dependencies";
let help_txt =
"scope `hint-mostly-unused` to specific packages with a lot of unused object code";
Expand Down Expand Up @@ -177,6 +175,7 @@ pub fn blanket_hint_mostly_unused(
// The primary group should always be first
report.insert(0, primary_group);

stats.record_lint(lint_level);
gctx.shell().print_report(&report, lint_level.force())?;
}

Expand Down
7 changes: 3 additions & 4 deletions src/cargo/diagnostics/rules/im_a_teapot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::CargoResult;
use crate::GlobalContext;
use crate::core::Feature;
use crate::core::Package;
use crate::diagnostics::DiagnosticStats;
use crate::diagnostics::Lint;
use crate::diagnostics::LintLevel;
use crate::diagnostics::get_key_value_span;
Expand All @@ -33,7 +34,7 @@ pub fn check_im_a_teapot(
pkg: &Package,
path: &Path,
pkg_lints: &TomlToolLints,
error_count: &mut usize,
stats: &mut DiagnosticStats,
gctx: &GlobalContext,
) -> CargoResult<()> {
let manifest = pkg.manifest();
Expand All @@ -49,9 +50,6 @@ pub fn check_im_a_teapot(
.package()
.is_some_and(|p| p.im_a_teapot.is_some())
{
if lint_level.is_error() {
*error_count += 1;
}
let level = lint_level.to_diagnostic_level();
let manifest_path = rel_cwd_manifest_path(path, gctx);
let emitted_source = LINT.emitted_source(lint_level, source);
Expand All @@ -74,6 +72,7 @@ pub fn check_im_a_teapot(

let report = &[desc.element(Level::NOTE.message(&emitted_source))];

stats.record_lint(lint_level);
gctx.shell().print_report(report, lint_level.force())?;
}
Ok(())
Expand Down
Loading
Loading