mirror of https://github.com/rust-lang/cargo
feat: Add a basic linting system
This commit is contained in:
parent
abf0953292
commit
307c7f825c
|
@ -3428,9 +3428,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.7"
|
||||
version = "0.22.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18769cd1cec395d70860ceb4d932812a0b4d06b1a4bb336745a4d21b9496e992"
|
||||
checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
|
|
|
@ -97,7 +97,7 @@ tempfile = "3.10.1"
|
|||
thiserror = "1.0.57"
|
||||
time = { version = "0.3", features = ["parsing", "formatting", "serde"] }
|
||||
toml = "0.8.10"
|
||||
toml_edit = { version = "0.22.7", features = ["serde"] }
|
||||
toml_edit = { version = "0.22.9", features = ["serde"] }
|
||||
tracing = "0.1.40" # be compatible with rustc_log: https://github.com/rust-lang/rust/blob/e51e98dde6a/compiler/rustc_log/Cargo.toml#L9
|
||||
tracing-chrome = "0.7.1"
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||
|
|
|
@ -24,10 +24,12 @@ 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;
|
||||
use crate::util::toml::{read_manifest, InheritableFields};
|
||||
use crate::util::{context::ConfigRelativePath, Filesystem, GlobalContext, IntoUrl};
|
||||
use cargo_util::paths;
|
||||
use cargo_util::paths::normalize_path;
|
||||
use cargo_util_schemas::manifest;
|
||||
use cargo_util_schemas::manifest::RustVersion;
|
||||
use cargo_util_schemas::manifest::{TomlDependency, TomlProfiles};
|
||||
use pathdiff::diff_paths;
|
||||
|
@ -1095,11 +1097,14 @@ impl<'gctx> Workspace<'gctx> {
|
|||
|
||||
pub fn emit_warnings(&self) -> CargoResult<()> {
|
||||
for (path, maybe_pkg) in &self.packages.packages {
|
||||
let path = path.join("Cargo.toml");
|
||||
if let MaybePackage::Package(pkg) = maybe_pkg {
|
||||
self.emit_lints(pkg, &path)?
|
||||
}
|
||||
let warnings = match maybe_pkg {
|
||||
MaybePackage::Package(pkg) => pkg.manifest().warnings().warnings(),
|
||||
MaybePackage::Virtual(vm) => vm.warnings().warnings(),
|
||||
};
|
||||
let path = path.join("Cargo.toml");
|
||||
for warning in warnings {
|
||||
if warning.is_critical {
|
||||
let err = anyhow::format_err!("{}", warning.message);
|
||||
|
@ -1121,6 +1126,30 @@ impl<'gctx> Workspace<'gctx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn emit_lints(&self, pkg: &Package, path: &Path) -> CargoResult<()> {
|
||||
let mut error_count = 0;
|
||||
let lints = pkg
|
||||
.manifest()
|
||||
.resolved_toml()
|
||||
.lints
|
||||
.clone()
|
||||
.map(|lints| lints.lints)
|
||||
.unwrap_or(manifest::TomlLints::default())
|
||||
.get("cargo")
|
||||
.cloned()
|
||||
.unwrap_or(manifest::TomlToolLints::default());
|
||||
|
||||
check_implicit_features(pkg, &path, &lints, &mut error_count, self.gctx)?;
|
||||
if error_count > 0 {
|
||||
Err(crate::util::errors::AlreadyPrintedError::new(anyhow!(
|
||||
"encountered {error_count} errors(s) while running lints"
|
||||
))
|
||||
.into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_target_dir(&mut self, target_dir: Filesystem) {
|
||||
self.target_dir = Some(target_dir);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
use crate::core::FeatureValue::Dep;
|
||||
use crate::core::{Edition, FeatureValue, Package};
|
||||
use crate::util::interning::InternedString;
|
||||
use crate::{CargoResult, GlobalContext};
|
||||
use annotate_snippets::{Level, Renderer, Snippet};
|
||||
use cargo_util_schemas::manifest::{TomlLintLevel, TomlToolLints};
|
||||
use pathdiff::diff_paths;
|
||||
use std::collections::HashSet;
|
||||
use std::ops::Range;
|
||||
use std::path::Path;
|
||||
use toml_edit::ImDocument;
|
||||
|
||||
fn get_span(document: &ImDocument<String>, path: &[&str], get_value: bool) -> Option<Range<usize>> {
|
||||
let mut table = document.as_item().as_table_like().unwrap();
|
||||
let mut iter = path.into_iter().peekable();
|
||||
while let Some(key) = iter.next() {
|
||||
let (key, item) = table.get_key_value(key).unwrap();
|
||||
if iter.peek().is_none() {
|
||||
return if get_value {
|
||||
item.span()
|
||||
} else {
|
||||
let leaf_decor = key.dotted_decor();
|
||||
let leaf_prefix_span = leaf_decor.prefix().and_then(|p| p.span());
|
||||
let leaf_suffix_span = leaf_decor.suffix().and_then(|s| s.span());
|
||||
if let (Some(leaf_prefix_span), Some(leaf_suffix_span)) =
|
||||
(leaf_prefix_span, leaf_suffix_span)
|
||||
{
|
||||
Some(leaf_prefix_span.start..leaf_suffix_span.end)
|
||||
} else {
|
||||
key.span()
|
||||
}
|
||||
};
|
||||
}
|
||||
if item.is_table_like() {
|
||||
table = item.as_table_like().unwrap();
|
||||
}
|
||||
if item.is_array() && iter.peek().is_some() {
|
||||
let array = item.as_array().unwrap();
|
||||
let next = iter.next().unwrap();
|
||||
return array.iter().find_map(|item| {
|
||||
if next == &item.to_string() {
|
||||
item.span()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Gets the relative path to a manifest from the current working directory, or
|
||||
/// the absolute path of the manifest if a relative path cannot be constructed
|
||||
fn rel_cwd_manifest_path(path: &Path, gctx: &GlobalContext) -> String {
|
||||
diff_paths(path, gctx.cwd())
|
||||
.unwrap_or_else(|| path.to_path_buf())
|
||||
.display()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct LintGroup {
|
||||
pub name: &'static str,
|
||||
pub default_level: LintLevel,
|
||||
pub desc: &'static str,
|
||||
pub edition_lint_opts: Option<(Edition, LintLevel)>,
|
||||
}
|
||||
|
||||
const RUST_2024_COMPATIBILITY: LintGroup = LintGroup {
|
||||
name: "rust-2024-compatibility",
|
||||
default_level: LintLevel::Allow,
|
||||
desc: "warn about compatibility with Rust 2024",
|
||||
edition_lint_opts: Some((Edition::Edition2024, LintLevel::Deny)),
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Lint {
|
||||
pub name: &'static str,
|
||||
pub desc: &'static str,
|
||||
pub groups: &'static [LintGroup],
|
||||
pub default_level: LintLevel,
|
||||
pub edition_lint_opts: Option<(Edition, LintLevel)>,
|
||||
}
|
||||
|
||||
impl Lint {
|
||||
pub fn level(&self, lints: &TomlToolLints, edition: Edition) -> LintLevel {
|
||||
let level = self
|
||||
.groups
|
||||
.iter()
|
||||
.map(|g| g.name)
|
||||
.chain(std::iter::once(self.name))
|
||||
.filter_map(|n| lints.get(n).map(|l| (n, l)))
|
||||
.max_by_key(|(n, l)| (l.priority(), std::cmp::Reverse(*n)));
|
||||
|
||||
match level {
|
||||
Some((_, toml_lint)) => toml_lint.level().into(),
|
||||
None => {
|
||||
if let Some((lint_edition, lint_level)) = self.edition_lint_opts {
|
||||
if edition >= lint_edition {
|
||||
return lint_level;
|
||||
}
|
||||
}
|
||||
self.default_level
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum LintLevel {
|
||||
Allow,
|
||||
Warn,
|
||||
Deny,
|
||||
Forbid,
|
||||
}
|
||||
|
||||
impl LintLevel {
|
||||
pub fn to_diagnostic_level(self) -> Level {
|
||||
match self {
|
||||
LintLevel::Allow => Level::Note,
|
||||
LintLevel::Warn => Level::Warning,
|
||||
LintLevel::Deny => Level::Error,
|
||||
LintLevel::Forbid => Level::Error,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TomlLintLevel> for LintLevel {
|
||||
fn from(toml_lint_level: TomlLintLevel) -> LintLevel {
|
||||
match toml_lint_level {
|
||||
TomlLintLevel::Allow => LintLevel::Allow,
|
||||
TomlLintLevel::Warn => LintLevel::Warn,
|
||||
TomlLintLevel::Deny => LintLevel::Deny,
|
||||
TomlLintLevel::Forbid => LintLevel::Forbid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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:<name>` (see [RFC #3143]).
|
||||
///
|
||||
/// In the 2024 edition, `cargo` will stop exposing optional dependencies as
|
||||
/// features implicitly, requiring users to add `foo = ["dep:foo"]` if they
|
||||
/// still want it exposed.
|
||||
///
|
||||
/// For more information, see [RFC #3491]
|
||||
///
|
||||
/// [feature]: https://doc.rust-lang.org/cargo/reference/features.html
|
||||
/// [RFC #3143]: https://rust-lang.github.io/rfcs/3143-cargo-weak-namespaced-features.html
|
||||
/// [RFC #3491]: https://rust-lang.github.io/rfcs/3491-remove-implicit-features.html
|
||||
const IMPLICIT_FEATURES: Lint = Lint {
|
||||
name: "implicit-features",
|
||||
desc: "warn about the use of unstable features",
|
||||
groups: &[RUST_2024_COMPATIBILITY],
|
||||
default_level: LintLevel::Allow,
|
||||
edition_lint_opts: Some((Edition::Edition2024, LintLevel::Deny)),
|
||||
};
|
||||
|
||||
pub fn check_implicit_features(
|
||||
pkg: &Package,
|
||||
path: &Path,
|
||||
lints: &TomlToolLints,
|
||||
error_count: &mut usize,
|
||||
gctx: &GlobalContext,
|
||||
) -> CargoResult<()> {
|
||||
let lint_level = IMPLICIT_FEATURES.level(lints, pkg.manifest().edition());
|
||||
if lint_level == LintLevel::Allow {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let manifest = pkg.manifest();
|
||||
let user_defined_features = manifest.resolved_toml().features();
|
||||
let features = user_defined_features.map_or(HashSet::new(), |f| {
|
||||
f.keys().map(|k| InternedString::new(&k)).collect()
|
||||
});
|
||||
// Add implicit features for optional dependencies if they weren't
|
||||
// explicitly listed anywhere.
|
||||
let explicitly_listed = user_defined_features.map_or(HashSet::new(), |f| {
|
||||
f.values()
|
||||
.flatten()
|
||||
.filter_map(|v| match FeatureValue::new(v.into()) {
|
||||
Dep { dep_name } => Some(dep_name),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
|
||||
for dep in manifest.dependencies() {
|
||||
let dep_name_in_toml = dep.name_in_toml();
|
||||
if !dep.is_optional()
|
||||
|| features.contains(&dep_name_in_toml)
|
||||
|| explicitly_listed.contains(&dep_name_in_toml)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
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 message = level.title("unused optional dependency").snippet(
|
||||
Snippet::source(manifest.contents())
|
||||
.origin(&manifest_path)
|
||||
.annotation(
|
||||
level.span(
|
||||
get_span(
|
||||
manifest.document(),
|
||||
&["dependencies", &dep_name_in_toml],
|
||||
false,
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
)
|
||||
.fold(true),
|
||||
);
|
||||
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(())
|
||||
}
|
|
@ -51,6 +51,7 @@ pub mod into_url;
|
|||
mod into_url_with_base;
|
||||
mod io;
|
||||
pub mod job;
|
||||
pub mod lints;
|
||||
mod lockserver;
|
||||
pub mod machine_message;
|
||||
pub mod network;
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
use cargo_test_support::prelude::*;
|
||||
use cargo_test_support::project;
|
||||
use cargo_test_support::registry::Package;
|
||||
use cargo_test_support::str;
|
||||
|
||||
#[cargo_test]
|
||||
fn case() {
|
||||
Package::new("bar", "0.1.0").publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bar = { version = "0.1.0", optional = true }
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
snapbox::cmd::Command::cargo_ui()
|
||||
.masquerade_as_nightly_cargo(&["always_nightly"])
|
||||
.current_dir(p.root())
|
||||
.arg("check")
|
||||
.arg("--quiet")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout_matches(str![""])
|
||||
.stderr_matches(str![""]);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
use cargo_test_support::prelude::*;
|
||||
use cargo_test_support::registry::Package;
|
||||
use cargo_test_support::str;
|
||||
use cargo_test_support::{file, project};
|
||||
|
||||
#[cargo_test]
|
||||
fn case() {
|
||||
Package::new("bar", "0.1.0").publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bar = { version = "0.1.0", optional = true }
|
||||
|
||||
[lints.cargo]
|
||||
implicit-features = "warn"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
snapbox::cmd::Command::cargo_ui()
|
||||
.masquerade_as_nightly_cargo(&["always_nightly"])
|
||||
.current_dir(p.root())
|
||||
.arg("check")
|
||||
.arg("--quiet")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout_matches(str![""])
|
||||
.stderr_matches(file!["stderr.term.svg"]);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<svg width="740px" height="146px" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
.fg { fill: #AAAAAA }
|
||||
.bg { background: #000000 }
|
||||
.fg-bright-blue { fill: #5555FF }
|
||||
.fg-yellow { fill: #AA5500 }
|
||||
.container {
|
||||
padding: 0 10px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.bold { font-weight: bold; }
|
||||
tspan {
|
||||
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||
white-space: pre;
|
||||
line-height: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
|
||||
|
||||
<text xml:space="preserve" class="container fg">
|
||||
<tspan x="10px" y="28px"><tspan class="fg-yellow bold">warning</tspan><tspan>: </tspan><tspan class="bold">unused optional dependency</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--></tspan><tspan> Cargo.toml:8:1</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="64px"><tspan class="fg-bright-blue bold"> |</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">8 |</tspan><tspan> bar = { version = "0.1.0", optional = true }</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="100px"><tspan class="fg-bright-blue bold"> |</tspan><tspan class="fg-yellow bold"> ---</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold"> |</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="136px">
|
||||
</tspan>
|
||||
</text>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,39 @@
|
|||
use cargo_test_support::prelude::*;
|
||||
use cargo_test_support::registry::Package;
|
||||
use cargo_test_support::str;
|
||||
use cargo_test_support::{file, project};
|
||||
|
||||
#[cargo_test(nightly, reason = "edition2024 is not stable")]
|
||||
fn case() {
|
||||
Package::new("bar", "0.1.0").publish();
|
||||
Package::new("baz", "0.1.0").publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
cargo-features = ["edition2024"]
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
bar = { version = "0.1.0", optional = true }
|
||||
baz = { version = "0.1.0", optional = true }
|
||||
|
||||
[features]
|
||||
baz = ["dep:baz"]
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
snapbox::cmd::Command::cargo_ui()
|
||||
.masquerade_as_nightly_cargo(&["always_nightly"])
|
||||
.current_dir(p.root())
|
||||
.arg("check")
|
||||
.assert()
|
||||
.code(101)
|
||||
.stdout_matches(str![""])
|
||||
.stderr_matches(file!["stderr.term.svg"]);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<svg width="740px" height="146px" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
.fg { fill: #AAAAAA }
|
||||
.bg { background: #000000 }
|
||||
.fg-bright-blue { fill: #5555FF }
|
||||
.fg-bright-red { fill: #FF5555 }
|
||||
.container {
|
||||
padding: 0 10px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.bold { font-weight: bold; }
|
||||
tspan {
|
||||
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||
white-space: pre;
|
||||
line-height: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
|
||||
|
||||
<text xml:space="preserve" class="container fg">
|
||||
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error</tspan><tspan>: </tspan><tspan class="bold">unused optional dependency</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--></tspan><tspan> Cargo.toml:9:1</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="64px"><tspan class="fg-bright-blue bold"> |</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">9 |</tspan><tspan> bar = { version = "0.1.0", optional = true }</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="100px"><tspan class="fg-bright-blue bold"> |</tspan><tspan class="fg-bright-red bold"> ^^^</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold"> |</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="136px">
|
||||
</tspan>
|
||||
</text>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,4 @@
|
|||
mod edition_2021;
|
||||
mod edition_2021_warn;
|
||||
mod edition_2024;
|
||||
mod warn;
|
|
@ -0,0 +1,38 @@
|
|||
use cargo_test_support::prelude::*;
|
||||
use cargo_test_support::registry::Package;
|
||||
use cargo_test_support::str;
|
||||
use cargo_test_support::{file, project};
|
||||
|
||||
#[cargo_test(nightly, reason = "edition2024 is not stable")]
|
||||
fn case() {
|
||||
Package::new("bar", "0.1.0").publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
cargo-features = ["edition2024"]
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
bar = { version = "0.1.0", optional = true }
|
||||
|
||||
[lints.cargo]
|
||||
implicit-features = "warn"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
snapbox::cmd::Command::cargo_ui()
|
||||
.masquerade_as_nightly_cargo(&["always_nightly"])
|
||||
.current_dir(p.root())
|
||||
.arg("check")
|
||||
.arg("--quiet")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout_matches(str![""])
|
||||
.stderr_matches(file!["stderr.term.svg"]);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<svg width="740px" height="146px" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
.fg { fill: #AAAAAA }
|
||||
.bg { background: #000000 }
|
||||
.fg-bright-blue { fill: #5555FF }
|
||||
.fg-yellow { fill: #AA5500 }
|
||||
.container {
|
||||
padding: 0 10px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.bold { font-weight: bold; }
|
||||
tspan {
|
||||
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||
white-space: pre;
|
||||
line-height: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
|
||||
|
||||
<text xml:space="preserve" class="container fg">
|
||||
<tspan x="10px" y="28px"><tspan class="fg-yellow bold">warning</tspan><tspan>: </tspan><tspan class="bold">unused optional dependency</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--></tspan><tspan> Cargo.toml:9:1</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="64px"><tspan class="fg-bright-blue bold"> |</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">9 |</tspan><tspan> bar = { version = "0.1.0", optional = true }</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="100px"><tspan class="fg-bright-blue bold"> |</tspan><tspan class="fg-yellow bold"> ---</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold"> |</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="136px">
|
||||
</tspan>
|
||||
</text>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,2 @@
|
|||
mod implicit_features;
|
||||
mod rust_2024_compatibility;
|
|
@ -0,0 +1,34 @@
|
|||
use cargo_test_support::prelude::*;
|
||||
use cargo_test_support::project;
|
||||
use cargo_test_support::registry::Package;
|
||||
use cargo_test_support::str;
|
||||
|
||||
#[cargo_test]
|
||||
fn case() {
|
||||
Package::new("bar", "0.1.0").publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bar = { version = "0.1.0", optional = true }
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
snapbox::cmd::Command::cargo_ui()
|
||||
.masquerade_as_nightly_cargo(&["always_nightly"])
|
||||
.current_dir(p.root())
|
||||
.arg("check")
|
||||
.arg("--quiet")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout_matches(str![""])
|
||||
.stderr_matches(str![""]);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
use cargo_test_support::prelude::*;
|
||||
use cargo_test_support::registry::Package;
|
||||
use cargo_test_support::str;
|
||||
use cargo_test_support::{file, project};
|
||||
|
||||
#[cargo_test]
|
||||
fn case() {
|
||||
Package::new("bar", "0.1.0").publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bar = { version = "0.1.0", optional = true }
|
||||
|
||||
[lints.cargo]
|
||||
rust-2024-compatibility = "warn"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
snapbox::cmd::Command::cargo_ui()
|
||||
.masquerade_as_nightly_cargo(&["always_nightly"])
|
||||
.current_dir(p.root())
|
||||
.arg("check")
|
||||
.arg("--quiet")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout_matches(str![""])
|
||||
.stderr_matches(file!["stderr.term.svg"]);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<svg width="740px" height="146px" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
.fg { fill: #AAAAAA }
|
||||
.bg { background: #000000 }
|
||||
.fg-bright-blue { fill: #5555FF }
|
||||
.fg-yellow { fill: #AA5500 }
|
||||
.container {
|
||||
padding: 0 10px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.bold { font-weight: bold; }
|
||||
tspan {
|
||||
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||
white-space: pre;
|
||||
line-height: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
|
||||
|
||||
<text xml:space="preserve" class="container fg">
|
||||
<tspan x="10px" y="28px"><tspan class="fg-yellow bold">warning</tspan><tspan>: </tspan><tspan class="bold">unused optional dependency</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--></tspan><tspan> Cargo.toml:8:1</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="64px"><tspan class="fg-bright-blue bold"> |</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">8 |</tspan><tspan> bar = { version = "0.1.0", optional = true }</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="100px"><tspan class="fg-bright-blue bold"> |</tspan><tspan class="fg-yellow bold"> ---</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold"> |</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="136px">
|
||||
</tspan>
|
||||
</text>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,34 @@
|
|||
use cargo_test_support::prelude::*;
|
||||
use cargo_test_support::registry::Package;
|
||||
use cargo_test_support::str;
|
||||
use cargo_test_support::{file, project};
|
||||
|
||||
#[cargo_test(nightly, reason = "edition2024 is not stable")]
|
||||
fn case() {
|
||||
Package::new("bar", "0.1.0").publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
cargo-features = ["edition2024"]
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
bar = { version = "0.1.0", optional = true }
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
snapbox::cmd::Command::cargo_ui()
|
||||
.masquerade_as_nightly_cargo(&["always_nightly"])
|
||||
.current_dir(p.root())
|
||||
.arg("check")
|
||||
.assert()
|
||||
.code(101)
|
||||
.stdout_matches(str![""])
|
||||
.stderr_matches(file!["stderr.term.svg"]);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<svg width="740px" height="146px" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
.fg { fill: #AAAAAA }
|
||||
.bg { background: #000000 }
|
||||
.fg-bright-blue { fill: #5555FF }
|
||||
.fg-bright-red { fill: #FF5555 }
|
||||
.container {
|
||||
padding: 0 10px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.bold { font-weight: bold; }
|
||||
tspan {
|
||||
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||
white-space: pre;
|
||||
line-height: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
|
||||
|
||||
<text xml:space="preserve" class="container fg">
|
||||
<tspan x="10px" y="28px"><tspan class="fg-bright-red bold">error</tspan><tspan>: </tspan><tspan class="bold">unused optional dependency</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--></tspan><tspan> Cargo.toml:9:1</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="64px"><tspan class="fg-bright-blue bold"> |</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">9 |</tspan><tspan> bar = { version = "0.1.0", optional = true }</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="100px"><tspan class="fg-bright-blue bold"> |</tspan><tspan class="fg-bright-red bold"> ^^^</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold"> |</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="136px">
|
||||
</tspan>
|
||||
</text>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,4 @@
|
|||
mod edition_2021;
|
||||
mod edition_2021_warn;
|
||||
mod edition_2024;
|
||||
mod warn;
|
|
@ -0,0 +1,38 @@
|
|||
use cargo_test_support::prelude::*;
|
||||
use cargo_test_support::registry::Package;
|
||||
use cargo_test_support::str;
|
||||
use cargo_test_support::{file, project};
|
||||
|
||||
#[cargo_test(nightly, reason = "edition2024 is not stable")]
|
||||
fn case() {
|
||||
Package::new("bar", "0.1.0").publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
cargo-features = ["edition2024"]
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
bar = { version = "0.1.0", optional = true }
|
||||
|
||||
[lints.cargo]
|
||||
rust-2024-compatibility = "warn"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
snapbox::cmd::Command::cargo_ui()
|
||||
.masquerade_as_nightly_cargo(&["always_nightly"])
|
||||
.current_dir(p.root())
|
||||
.arg("check")
|
||||
.arg("--quiet")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout_matches(str![""])
|
||||
.stderr_matches(file!["stderr.term.svg"]);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<svg width="740px" height="146px" xmlns="http://www.w3.org/2000/svg">
|
||||
<style>
|
||||
.fg { fill: #AAAAAA }
|
||||
.bg { background: #000000 }
|
||||
.fg-bright-blue { fill: #5555FF }
|
||||
.fg-yellow { fill: #AA5500 }
|
||||
.container {
|
||||
padding: 0 10px;
|
||||
line-height: 18px;
|
||||
}
|
||||
.bold { font-weight: bold; }
|
||||
tspan {
|
||||
font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
|
||||
white-space: pre;
|
||||
line-height: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
|
||||
|
||||
<text xml:space="preserve" class="container fg">
|
||||
<tspan x="10px" y="28px"><tspan class="fg-yellow bold">warning</tspan><tspan>: </tspan><tspan class="bold">unused optional dependency</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="46px"><tspan> </tspan><tspan class="fg-bright-blue bold">--></tspan><tspan> Cargo.toml:9:1</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="64px"><tspan class="fg-bright-blue bold"> |</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="82px"><tspan class="fg-bright-blue bold">9 |</tspan><tspan> bar = { version = "0.1.0", optional = true }</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="100px"><tspan class="fg-bright-blue bold"> |</tspan><tspan class="fg-yellow bold"> ---</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="118px"><tspan class="fg-bright-blue bold"> |</tspan>
|
||||
</tspan>
|
||||
<tspan x="10px" y="136px">
|
||||
</tspan>
|
||||
</text>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -107,6 +107,7 @@ mod inheritable_workspace_fields;
|
|||
mod install;
|
||||
mod install_upgrade;
|
||||
mod jobserver;
|
||||
mod lints;
|
||||
mod lints_table;
|
||||
mod list_availables;
|
||||
mod local_registry;
|
||||
|
|
Loading…
Reference in New Issue