diff --git a/src/cargo/core/workspace.rs b/src/cargo/core/workspace.rs index 9fb6814f5d3..3a6bd11924d 100644 --- a/src/cargo/core/workspace.rs +++ b/src/cargo/core/workspace.rs @@ -24,7 +24,7 @@ use crate::sources::{PathSource, CRATES_IO_INDEX, CRATES_IO_REGISTRY}; use crate::util::edit_distance; use crate::util::errors::{CargoResult, ManifestError}; use crate::util::interning::InternedString; -use crate::util::lints::{check_implicit_features, unused_dependencies}; +use crate::util::lints::{check_im_a_teapot, check_implicit_features, unused_dependencies}; use crate::util::toml::{read_manifest, InheritableFields}; use crate::util::{ context::CargoResolverConfig, context::CargoResolverPrecedence, context::ConfigRelativePath, @@ -1206,6 +1206,7 @@ impl<'gctx> Workspace<'gctx> { .map(|(name, lint)| (name.replace('-', "_"), lint)) .collect(); + check_im_a_teapot(pkg, &path, &normalized_lints, &mut error_count, self.gctx)?; check_implicit_features(pkg, &path, &normalized_lints, &mut error_count, self.gctx)?; unused_dependencies(pkg, &path, &normalized_lints, &mut error_count, self.gctx)?; if error_count > 0 { diff --git a/src/cargo/util/lints.rs b/src/cargo/util/lints.rs index d891c13665b..204feb0459f 100644 --- a/src/cargo/util/lints.rs +++ b/src/cargo/util/lints.rs @@ -142,6 +142,61 @@ impl From for LintLevel { } } +const IM_A_TEAPOT: Lint = Lint { + name: "im_a_teapot", + desc: "`im_a_teapot` is specified", + groups: &[], + default_level: LintLevel::Allow, + edition_lint_opts: None, +}; + +pub fn check_im_a_teapot( + pkg: &Package, + path: &Path, + lints: &TomlToolLints, + error_count: &mut usize, + gctx: &GlobalContext, +) -> CargoResult<()> { + let manifest = pkg.manifest(); + let lint_level = IM_A_TEAPOT.level(lints, manifest.edition()); + if lint_level == LintLevel::Allow { + return Ok(()); + } + + if manifest + .resolved_toml() + .package() + .is_some_and(|p| p.im_a_teapot.is_some()) + { + if lint_level == LintLevel::Forbid || lint_level == LintLevel::Deny { + *error_count += 1; + } + let level = lint_level.to_diagnostic_level(); + let manifest_path = rel_cwd_manifest_path(path, gctx); + let emitted_reason = format!("`cargo::{}` is set to `{lint_level}`", IM_A_TEAPOT.name); + + let key_span = get_span(manifest.document(), &["package", "im-a-teapot"], false).unwrap(); + let value_span = get_span(manifest.document(), &["package", "im-a-teapot"], true).unwrap(); + let message = level + .title(IM_A_TEAPOT.desc) + .snippet( + Snippet::source(manifest.contents()) + .origin(&manifest_path) + .annotation(level.span(key_span.start..value_span.end)) + .fold(true), + ) + .footer(Level::Note.title(&emitted_reason)); + let renderer = Renderer::styled().term_width( + gctx.shell() + .err_width() + .diagnostic_terminal_width() + .unwrap_or(annotate_snippets::renderer::DEFAULT_TERM_WIDTH), + ); + writeln!(gctx.shell().err(), "{}", renderer.render(message))?; + } + Ok(()) +} + /// By default, cargo will treat any optional dependency as a [feature]. As of /// cargo 1.60, these can be disabled by declaring a feature that activates the /// optional dependency as `dep:` (see [RFC #3143]). diff --git a/tests/testsuite/lints_table.rs b/tests/testsuite/lints_table.rs index 15d976fa1e8..27d840f07f2 100644 --- a/tests/testsuite/lints_table.rs +++ b/tests/testsuite/lints_table.rs @@ -756,14 +756,14 @@ fn cargo_lints_nightly_required() { .file( "Cargo.toml", r#" - [package] - name = "foo" - version = "0.0.1" - edition = "2015" - authors = [] - - [lints.cargo] - "unused-features" = "deny" +[package] +name = "foo" +version = "0.0.1" +edition = "2015" +authors = [] + +[lints.cargo] +im-a-teapot = "warn" "#, ) .file("src/lib.rs", "") @@ -790,21 +790,24 @@ fn cargo_lints_no_z_flag() { .file( "Cargo.toml", r#" - [package] - name = "foo" - version = "0.0.1" - edition = "2015" - authors = [] +cargo-features = ["test-dummy-unstable"] + +[package] +name = "foo" +version = "0.0.1" +edition = "2015" +authors = [] +im-a-teapot = true - [lints.cargo] - "unused-features" = "deny" +[lints.cargo] +im-a-teapot = "warn" "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check") - .masquerade_as_nightly_cargo(&["-Zcargo-lints"]) + .masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"]) .with_stderr( "\ [WARNING] unused manifest key `lints.cargo` (may be supported in a future version) @@ -819,27 +822,37 @@ consider passing `-Zcargo-lints` to enable this feature. #[cargo_test] fn cargo_lints_success() { - let foo = project() + let p = project() .file( "Cargo.toml", r#" - [package] - name = "foo" - version = "0.0.1" - edition = "2015" - authors = [] +cargo-features = ["test-dummy-unstable"] + +[package] +name = "foo" +version = "0.0.1" +edition = "2015" +authors = [] +im-a-teapot = true - [lints.cargo] - "unused-features" = "deny" +[lints.cargo] +im-a-teapot = "warn" "#, ) .file("src/lib.rs", "") .build(); - foo.cargo("check -Zcargo-lints") - .masquerade_as_nightly_cargo(&["-Zcargo-lints"]) + p.cargo("check -Zcargo-lints") + .masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"]) .with_stderr( "\ +warning: `im_a_teapot` is specified + --> Cargo.toml:9:1 + | +9 | im-a-teapot = true + | ------------------ + | + = note: `cargo::im_a_teapot` is set to `warn` [CHECKING] foo v0.0.1 ([CWD]) [FINISHED] [..] ", @@ -849,40 +862,37 @@ fn cargo_lints_success() { #[cargo_test] fn cargo_lints_underscore_supported() { - Package::new("bar", "0.1.0").publish(); let foo = project() .file( "Cargo.toml", r#" - [package] - name = "foo" - version = "0.0.1" - edition = "2021" - authors = [] +cargo-features = ["test-dummy-unstable"] - [lints.cargo] - "implicit_features" = "warn" +[package] +name = "foo" +version = "0.0.1" +edition = "2015" +authors = [] +im-a-teapot = true - [dependencies] - bar = { version = "0.1.0", optional = true } +[lints.cargo] +im_a_teapot = "warn" "#, ) .file("src/lib.rs", "") .build(); foo.cargo("check -Zcargo-lints") - .masquerade_as_nightly_cargo(&["-Zcargo-lints"]) + .masquerade_as_nightly_cargo(&["cargo-lints", "test-dummy-unstable"]) .with_stderr( "\ -warning: implicit features for optional dependencies is deprecated and will be unavailable in the 2024 edition - --> Cargo.toml:12:17 - | -12 | bar = { version = \"0.1.0\", optional = true } - | --- - | - = note: `cargo::implicit_features` is set to `warn` -[UPDATING] `dummy-registry` index -[LOCKING] [..] +warning: `im_a_teapot` is specified + --> Cargo.toml:9:1 + | +9 | im-a-teapot = true + | ------------------ + | + = note: `cargo::im_a_teapot` is set to `warn` [CHECKING] foo v0.0.1 ([CWD]) [FINISHED] [..] ",