diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 3d3afe5e801..ac0ff19272a 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -2000,9 +2000,9 @@ struct ManifestErrorContext { /// The path to the manifest. path: PathBuf, /// The locations of various spans within the manifest. - spans: toml::Spanned>, + spans: Option>>, /// The raw manifest contents. - contents: String, + contents: Option, /// A lookup for all the unambiguous renamings, mapping from the original package /// name to the renamed one. rename_table: HashMap, @@ -2117,6 +2117,7 @@ fn on_stderr_line_inner( static PRIV_DEP_REGEX: LazyLock = LazyLock::new(|| Regex::new("from private dependency '([A-Za-z0-9-_]+)'").unwrap()); if let Some(crate_name) = PRIV_DEP_REGEX.captures(diag).and_then(|m| m.get(1)) + && let Some(ref contents) = manifest.contents && let Some(span) = manifest.find_crate_span(crate_name.as_str()) { let rel_path = pathdiff::diff_paths(&manifest.path, &manifest.cwd) @@ -2128,7 +2129,7 @@ fn on_stderr_line_inner( crate_name.as_str() ))) .element( - Snippet::source(&manifest.contents) + Snippet::source(contents) .path(rel_path) .annotation(AnnotationKind::Context.span(span)), )]; @@ -2366,8 +2367,8 @@ impl ManifestErrorContext { let bcx = build_runner.bcx; ManifestErrorContext { path: unit.pkg.manifest_path().to_owned(), - spans: unit.pkg.manifest().document().clone(), - contents: unit.pkg.manifest().contents().to_owned(), + spans: unit.pkg.manifest().document().cloned(), + contents: unit.pkg.manifest().contents().map(String::from), requested_kinds: bcx.target_data.requested_kinds().to_owned(), host_name: bcx.rustc().host, rename_table, @@ -2408,9 +2409,13 @@ impl ManifestErrorContext { /// baz = { path = "../bar", package = "bar" } /// ``` fn find_crate_span(&self, unrenamed: &str) -> Option> { + let Some(ref spans) = self.spans else { + return None; + }; + let orig_name = self.rename_table.get(unrenamed)?.as_str(); - if let Some((k, v)) = get_key_value(&self.spans, &["dependencies", orig_name]) { + if let Some((k, v)) = get_key_value(&spans, &["dependencies", orig_name]) { // We make some effort to find the unrenamed text: in // // ``` @@ -2430,8 +2435,7 @@ impl ManifestErrorContext { // [target.x86_64-unknown-linux-gnu.dependencies] or // [target.'cfg(something)'.dependencies]. We filter out target tables // that don't match a requested target or a requested cfg. - if let Some(target) = self - .spans + if let Some(target) = spans .as_ref() .get("target") .and_then(|t| t.as_ref().as_table()) diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index eb24127775e..df74a94ed96 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -62,9 +62,9 @@ impl EitherManifest { #[derive(Clone, Debug)] pub struct Manifest { // alternate forms of manifests: - contents: Rc, - document: Rc>>, - original_toml: Rc, + contents: Option>, + document: Option>>>, + original_toml: Option>, normalized_toml: Rc, summary: Summary, @@ -109,9 +109,9 @@ pub struct Warnings(Vec); #[derive(Clone, Debug)] pub struct VirtualManifest { // alternate forms of manifests: - contents: Rc, - document: Rc>>, - original_toml: Rc, + contents: Option>, + document: Option>>>, + original_toml: Option>, normalized_toml: Rc, // this form of manifest: @@ -496,9 +496,9 @@ compact_debug! { impl Manifest { pub fn new( - contents: Rc, - document: Rc>>, - original_toml: Rc, + contents: Option>, + document: Option>>>, + original_toml: Option>, normalized_toml: Rc, summary: Summary, @@ -559,8 +559,8 @@ impl Manifest { } /// The raw contents of the original TOML - pub fn contents(&self) -> &str { - self.contents.as_str() + pub fn contents(&self) -> Option<&str> { + self.contents.as_deref().map(|c| c.as_str()) } /// See [`Manifest::normalized_toml`] for what "normalized" means pub fn to_normalized_contents(&self) -> CargoResult { @@ -568,12 +568,12 @@ impl Manifest { Ok(format!("{}\n{}", MANIFEST_PREAMBLE, toml)) } /// Collection of spans for the original TOML - pub fn document(&self) -> &toml::Spanned> { - &self.document + pub fn document(&self) -> Option<&toml::Spanned>> { + self.document.as_deref() } /// The [`TomlManifest`] as parsed from [`Manifest::document`] - pub fn original_toml(&self) -> &TomlManifest { - &self.original_toml + pub fn original_toml(&self) -> Option<&TomlManifest> { + self.original_toml.as_deref() } /// The [`TomlManifest`] with all fields expanded /// @@ -744,9 +744,9 @@ impl Manifest { impl VirtualManifest { pub fn new( - contents: Rc, - document: Rc>>, - original_toml: Rc, + contents: Option>, + document: Option>>>, + original_toml: Option>, normalized_toml: Rc, replace: Vec<(PackageIdSpec, Dependency)>, patch: HashMap>, @@ -769,16 +769,16 @@ impl VirtualManifest { } /// The raw contents of the original TOML - pub fn contents(&self) -> &str { - self.contents.as_str() + pub fn contents(&self) -> Option<&str> { + self.contents.as_deref().map(|c| c.as_str()) } /// Collection of spans for the original TOML - pub fn document(&self) -> &toml::Spanned> { - &self.document + pub fn document(&self) -> Option<&toml::Spanned>> { + self.document.as_deref() } /// The [`TomlManifest`] as parsed from [`VirtualManifest::document`] - pub fn original_toml(&self) -> &TomlManifest { - &self.original_toml + pub fn original_toml(&self) -> Option<&TomlManifest> { + self.original_toml.as_deref() } /// The [`TomlManifest`] with all fields expanded pub fn normalized_toml(&self) -> &TomlManifest { diff --git a/src/cargo/core/workspace.rs b/src/cargo/core/workspace.rs index 7c5517c71df..e13b919629d 100644 --- a/src/cargo/core/workspace.rs +++ b/src/cargo/core/workspace.rs @@ -1985,14 +1985,14 @@ impl MaybePackage { } } - pub fn contents(&self) -> &str { + pub fn contents(&self) -> Option<&str> { match self { MaybePackage::Package(p) => p.manifest().contents(), MaybePackage::Virtual(v) => v.contents(), } } - pub fn document(&self) -> &toml::Spanned> { + pub fn document(&self) -> Option<&toml::Spanned>> { match self { MaybePackage::Package(p) => p.manifest().document(), MaybePackage::Virtual(v) => v.document(), diff --git a/src/cargo/lints/mod.rs b/src/cargo/lints/mod.rs index c9bf3c35bef..f6de5751954 100644 --- a/src/cargo/lints/mod.rs +++ b/src/cargo/lints/mod.rs @@ -2,6 +2,7 @@ use crate::core::{Edition, Feature, Features, MaybePackage, Package}; use crate::{CargoResult, GlobalContext}; use annotate_snippets::AnnotationKind; +use annotate_snippets::Group; use annotate_snippets::Level; use annotate_snippets::Snippet; use cargo_util_schemas::manifest::TomlLintLevel; @@ -31,14 +32,14 @@ impl ManifestFor<'_> { lint.level(pkg_lints, self.edition(), self.unstable_features()) } - pub fn contents(&self) -> &str { + pub fn contents(&self) -> Option<&str> { match self { ManifestFor::Package(p) => p.manifest().contents(), ManifestFor::Workspace(p) => p.contents(), } } - pub fn document(&self) -> &toml::Spanned> { + pub fn document(&self) -> Option<&toml::Spanned>> { match self { ManifestFor::Package(p) => p.manifest().document(), ManifestFor::Workspace(p) => p.document(), @@ -164,8 +165,6 @@ fn report_feature_not_enabled( error_count: &mut usize, gctx: &GlobalContext, ) -> CargoResult<()> { - let document = manifest.document(); - let contents = manifest.contents(); let dash_feature_name = feature_gate.name().replace("_", "-"); let title = format!("use of unstable lint `{}`", lint_name); let label = format!( @@ -181,19 +180,25 @@ fn report_feature_not_enabled( ManifestFor::Package(_) => &["lints", "cargo", lint_name][..], ManifestFor::Workspace(_) => &["workspace", "lints", "cargo", lint_name][..], }; - let Some(span) = get_key_value_span(document, key_path) else { - // This lint is handled by either package or workspace lint. - return Ok(()); - }; - let report = [Level::ERROR - .primary_title(title) - .element( + let mut error = Group::with_title(Level::ERROR.primary_title(title)); + + if let Some(document) = manifest.document() + && let Some(contents) = manifest.contents() + { + let Some(span) = get_key_value_span(document, key_path) else { + // This lint is handled by either package or workspace lint. + return Ok(()); + }; + + error = error.element( Snippet::source(contents) .path(manifest_path) .annotation(AnnotationKind::Primary.span(span.key).label(label)), ) - .element(Level::HELP.message(help))]; + } + + let report = [error.element(Level::HELP.message(help))]; *error_count += 1; gctx.shell().print_report(&report, true)?; diff --git a/src/cargo/lints/rules/blanket_hint_mostly_unused.rs b/src/cargo/lints/rules/blanket_hint_mostly_unused.rs index c95a6e82481..5de5763200c 100644 --- a/src/cargo/lints/rules/blanket_hint_mostly_unused.rs +++ b/src/cargo/lints/rules/blanket_hint_mostly_unused.rs @@ -1,7 +1,9 @@ use std::path::Path; use annotate_snippets::AnnotationKind; +use annotate_snippets::Group; use annotate_snippets::Level; +use annotate_snippets::Origin; use annotate_snippets::Patch; use annotate_snippets::Snippet; use cargo_util_schemas::manifest::ProfilePackageSpec; @@ -120,45 +122,58 @@ pub fn blanket_hint_mostly_unused( 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"; - if let (Some(span), Some(table_span)) = ( - get_key_value_span(maybe_pkg.document(), &path), - get_key_value_span(maybe_pkg.document(), &path[..path.len() - 1]), - ) { - let mut report = Vec::new(); - let mut primary_group = level.clone().primary_title(title).element( - Snippet::source(maybe_pkg.contents()) + + let mut report = Vec::new(); + let mut primary_group = Group::with_title(level.clone().primary_title(title)); + + if let Some(contents) = maybe_pkg.contents() + && let Some(document) = maybe_pkg.document() + && let Some(span) = get_key_value_span(document, &path) + && let Some(table_span) = get_key_value_span(document, &path[..path.len() - 1]) + { + primary_group = primary_group.element( + Snippet::source(contents) .path(&manifest_path) .annotation( AnnotationKind::Primary.span(table_span.key.start..table_span.key.end), ) .annotation(AnnotationKind::Context.span(span.key.start..span.value.end)), ); + } else { + primary_group = primary_group.element(Origin::path(&manifest_path)) + } - if *show_per_pkg_suggestion { - report.push( - Level::HELP.secondary_title(help_txt).element( - Snippet::source(maybe_pkg.contents()) - .path(&manifest_path) - .patch(Patch::new( - table_span.key.end..table_span.key.end, - ".package.", - )), - ), - ); - } else { - primary_group = primary_group.element(Level::HELP.message(help_txt)); - } + if *show_per_pkg_suggestion { + let help_group = Group::with_title(Level::HELP.secondary_title(help_txt)); + + report.push( + if let Some(contents) = maybe_pkg.contents() + && let Some(document) = maybe_pkg.document() + && let Some(table_span) = get_key_value_span(document, &path[..path.len() - 1]) + { + help_group.element(Snippet::source(contents).path(&manifest_path).patch( + Patch::new( + table_span.key.end..table_span.key.end, + ".package.", + ), + )) + } else { + help_group.element(Origin::path(&manifest_path)) + }, + ); + } else { + primary_group = primary_group.element(Level::HELP.message(help_txt)); + } - if i == 0 { - primary_group = primary_group - .element(Level::NOTE.message(LINT.emitted_source(lint_level, reason))); - } + if i == 0 { + primary_group = + primary_group.element(Level::NOTE.message(LINT.emitted_source(lint_level, reason))); + } - // The primary group should always be first - report.insert(0, primary_group); + // The primary group should always be first + report.insert(0, primary_group); - gctx.shell().print_report(&report, lint_level.force())?; - } + gctx.shell().print_report(&report, lint_level.force())?; } Ok(()) diff --git a/src/cargo/lints/rules/im_a_teapot.rs b/src/cargo/lints/rules/im_a_teapot.rs index 93e216986cc..ccf0b23647a 100644 --- a/src/cargo/lints/rules/im_a_teapot.rs +++ b/src/cargo/lints/rules/im_a_teapot.rs @@ -3,6 +3,7 @@ use std::path::Path; use annotate_snippets::AnnotationKind; use annotate_snippets::Group; use annotate_snippets::Level; +use annotate_snippets::Origin; use annotate_snippets::Snippet; use cargo_util_schemas::manifest::TomlToolLints; @@ -54,15 +55,23 @@ pub fn check_im_a_teapot( let manifest_path = rel_cwd_manifest_path(path, gctx); let emitted_reason = LINT.emitted_source(lint_level, reason); - let span = get_key_value_span(manifest.document(), &["package", "im-a-teapot"]).unwrap(); + let mut desc = Group::with_title(level.primary_title(LINT.desc)); - let report = &[Group::with_title(level.primary_title(LINT.desc)) - .element( - Snippet::source(manifest.contents()) + if let Some(document) = manifest.document() + && let Some(contents) = manifest.contents() + { + let span = get_key_value_span(document, &["package", "im-a-teapot"]).unwrap(); + + desc = desc.element( + Snippet::source(contents) .path(&manifest_path) .annotation(AnnotationKind::Primary.span(span.key.start..span.value.end)), - ) - .element(Level::NOTE.message(&emitted_reason))]; + ); + } else { + desc = desc.element(Origin::path(&manifest_path)); + } + + let report = &[desc.element(Level::NOTE.message(&emitted_reason))]; gctx.shell().print_report(report, lint_level.force())?; } diff --git a/src/cargo/lints/rules/implicit_minimum_version_req.rs b/src/cargo/lints/rules/implicit_minimum_version_req.rs index fefacfe88b9..8f9d7698f1e 100644 --- a/src/cargo/lints/rules/implicit_minimum_version_req.rs +++ b/src/cargo/lints/rules/implicit_minimum_version_req.rs @@ -4,6 +4,7 @@ use std::path::Path; use annotate_snippets::AnnotationKind; use annotate_snippets::Group; use annotate_snippets::Level; +use annotate_snippets::Origin; use annotate_snippets::Patch; use annotate_snippets::Snippet; use cargo_platform::Platform; @@ -139,18 +140,17 @@ pub fn lint_package( &[dep.kind().kind_table(), name_in_toml][..] }; - let Some(span) = span_of_version_req(document, key_path) else { - continue; - }; - - let report = report( + let Some(report) = report( lint_level, reason, - span, contents, + document, + key_path, &manifest_path, &suggested_req, - ); + ) else { + continue; + }; if lint_level.is_error() { *error_count += 1; @@ -205,18 +205,17 @@ pub fn lint_workspace( let key_path = ["workspace", "dependencies", name_in_toml]; - let Some(span) = span_of_version_req(document, &key_path) else { - continue; - }; - - let report = report( + let Some(report) = report( lint_level, reason, - span, contents, + document, + &key_path, &manifest_path, &suggested_req, - ); + ) else { + continue; + }; if lint_level.is_error() { *error_count += 1; @@ -252,27 +251,41 @@ pub fn span_of_version_req<'doc>( fn report<'a>( lint_level: LintLevel, reason: LintLevelReason, - span: std::ops::Range, - contents: &'a str, + contents: Option<&'a str>, + document: Option<&toml::Spanned>>, + key_path: &[&str], manifest_path: &str, suggested_req: &str, -) -> [Group<'a>; 2] { +) -> Option<[Group<'a>; 2]> { let level = lint_level.to_diagnostic_level(); let emitted_source = LINT.emitted_source(lint_level, reason); let replacement = format!(r#""{suggested_req}""#); let label = "missing full version components"; let secondary_title = "consider specifying full `major.minor.patch` version components"; - [ - level.clone().primary_title(LINT.desc).element( + + let mut desc = Group::with_title(level.primary_title(LINT.desc)); + let mut help = Group::with_title(Level::HELP.secondary_title(secondary_title)); + + if let Some(document) = document + && let Some(contents) = contents + { + let Some(span) = span_of_version_req(document, key_path) else { + return None; + }; + desc = desc.element( Snippet::source(contents) .path(manifest_path.to_owned()) .annotation(AnnotationKind::Primary.span(span.clone()).label(label)), - ), - Level::HELP - .secondary_title(secondary_title) + ); + help = help .element(Snippet::source(contents).patch(Patch::new(span.clone(), replacement))) - .element(Level::NOTE.message(emitted_source)), - ] + .element(Level::NOTE.message(emitted_source)); + } else { + desc = desc.element(Origin::path(manifest_path.to_owned())); + help = help.element(Level::NOTE.message(emitted_source)); + } + + Some([desc, help]) } fn get_suggested_version_req(req: &OptVersionReq) -> Option { diff --git a/src/cargo/lints/rules/unknown_lints.rs b/src/cargo/lints/rules/unknown_lints.rs index 64f66026434..e295ecc0cf8 100644 --- a/src/cargo/lints/rules/unknown_lints.rs +++ b/src/cargo/lints/rules/unknown_lints.rs @@ -1,6 +1,7 @@ use annotate_snippets::AnnotationKind; use annotate_snippets::Group; use annotate_snippets::Level; +use annotate_snippets::Origin; use annotate_snippets::Snippet; use cargo_util_schemas::manifest::TomlToolLints; @@ -53,9 +54,6 @@ pub fn output_unknown_lints( return Ok(()); } - let document = manifest.document(); - let contents = manifest.contents(); - let level = lint_level.to_diagnostic_level(); let mut emitted_source = None; for lint_name in unknown_lints { @@ -78,17 +76,26 @@ pub fn output_unknown_lints( ManifestFor::Package(_) => &["lints", "cargo", lint_name][..], ManifestFor::Workspace(_) => &["workspace", "lints", "cargo", lint_name][..], }; - let Some(span) = get_key_value_span(document, key_path) else { - // This lint is handled by either package or workspace lint. - return Ok(()); - }; let mut report = Vec::new(); - let mut group = Group::with_title(level.clone().primary_title(title)).element( - Snippet::source(contents) - .path(manifest_path) - .annotation(AnnotationKind::Primary.span(span.key)), - ); + let mut group = Group::with_title(level.clone().primary_title(title)); + + if let Some(document) = manifest.document() + && let Some(contents) = manifest.contents() + { + let Some(span) = get_key_value_span(document, key_path) else { + // This lint is handled by either package or workspace lint. + return Ok(()); + }; + group = group.element( + Snippet::source(contents) + .path(manifest_path) + .annotation(AnnotationKind::Primary.span(span.key)), + ); + } else { + group = group.element(Origin::path(manifest_path)); + } + if emitted_source.is_none() { emitted_source = Some(LINT.emitted_source(lint_level, reason)); group = group.element(Level::NOTE.message(emitted_source.as_ref().unwrap())); diff --git a/src/cargo/ops/fix/mod.rs b/src/cargo/ops/fix/mod.rs index 093463c81ca..bfb3cd6f70e 100644 --- a/src/cargo/ops/fix/mod.rs +++ b/src/cargo/ops/fix/mod.rs @@ -373,6 +373,7 @@ fn migrate_manifests( MaybePackage::Package(package) => package.manifest().original_toml(), MaybePackage::Virtual(manifest) => manifest.original_toml(), }; + if Edition::Edition2024 <= prepare_for_edition { let root = document.as_table_mut(); @@ -459,8 +460,12 @@ fn rename_dep_fields_2024(parent: &mut dyn toml_edit::TableLike, dep_kind: &str) fn remove_ignored_default_features_2024( parent: &mut dyn toml_edit::TableLike, dep_kind: &str, - ws_original_toml: &TomlManifest, + ws_original_toml: Option<&TomlManifest>, ) -> usize { + let Some(ws_original_toml) = ws_original_toml else { + return 0; + }; + let mut fixes = 0; for (name_in_toml, target) in parent .get_mut(dep_kind) diff --git a/src/cargo/ops/vendor.rs b/src/cargo/ops/vendor.rs index 2479abe9b07..d9e36b22cdd 100644 --- a/src/cargo/ops/vendor.rs +++ b/src/cargo/ops/vendor.rs @@ -511,8 +511,8 @@ fn prepare_for_vendor( let mut warnings = Default::default(); let mut errors = Default::default(); let manifest = crate::util::toml::to_real_manifest( - contents.to_owned(), - document.clone(), + contents.map(|c| c.to_owned()), + document.cloned(), original_toml, normalized_toml, features, diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index bbe411b6227..983ee7ca168 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -101,8 +101,8 @@ pub fn read_manifest( if normalized_toml.package().is_some() { to_real_manifest( - contents, - document, + Some(contents), + Some(document), original_toml, normalized_toml, features, @@ -118,8 +118,8 @@ pub fn read_manifest( } else if normalized_toml.workspace.is_some() { assert!(!is_embedded); to_virtual_manifest( - contents, - document, + Some(contents), + Some(document), original_toml, normalized_toml, features, @@ -1265,8 +1265,8 @@ fn deprecated_ws_default_features( #[tracing::instrument(skip_all)] pub fn to_real_manifest( - contents: String, - document: toml::Spanned>, + contents: Option, + document: Option>>, original_toml: manifest::TomlManifest, normalized_toml: manifest::TomlManifest, features: Features, @@ -1753,8 +1753,8 @@ pub fn to_real_manifest( missing_dep_diagnostic( missing_dep, &original_toml, - &document, - &contents, + document.as_ref(), + contents.as_deref(), manifest_file, gctx, )?; @@ -1815,9 +1815,9 @@ note: only a feature named `default` will be enabled by default" let default_run = normalized_package.default_run.clone(); let metabuild = normalized_package.metabuild.clone().map(|sov| sov.0); let manifest = Manifest::new( - Rc::new(contents), - Rc::new(document), - Rc::new(original_toml), + contents.map(Rc::new), + document.map(Rc::new), + Some(Rc::new(original_toml)), Rc::new(normalized_toml), summary, default_kind, @@ -1866,7 +1866,9 @@ note: only a feature named `default` will be enabled by default" .to_owned(), ); } - warn_on_unused(&manifest.original_toml()._unused_keys, warnings); + if let Some(original_toml) = manifest.original_toml() { + warn_on_unused(&original_toml._unused_keys, warnings); + } manifest.feature_gate()?; @@ -1876,15 +1878,13 @@ note: only a feature named `default` will be enabled by default" fn missing_dep_diagnostic( missing_dep: &MissingDependencyError, orig_toml: &TomlManifest, - document: &toml::Spanned>, - contents: &str, + document: Option<&toml::Spanned>>, + contents: Option<&str>, manifest_file: &Path, gctx: &GlobalContext, ) -> CargoResult<()> { let dep_name = missing_dep.dep_name; let manifest_path = rel_cwd_manifest_path(manifest_file, gctx); - let feature_span = - get_key_value_span(&document, &["features", missing_dep.feature.as_str()]).unwrap(); let title = format!( "feature `{}` includes `{}`, but `{}` is not a dependency", @@ -1896,57 +1896,67 @@ fn missing_dep_diagnostic( &dep_name ); let group = Group::with_title(Level::ERROR.primary_title(&title)); - let snippet = Snippet::source(contents) - .path(manifest_path) - .annotation(AnnotationKind::Primary.span(feature_span.value)); - let group = if missing_dep.weak_optional { - let mut orig_deps = vec![ - ( - orig_toml.dependencies.as_ref(), - vec![DepKind::Normal.kind_table()], - ), - ( - orig_toml.build_dependencies.as_ref(), - vec![DepKind::Build.kind_table()], - ), - ]; - for (name, platform) in orig_toml.target.iter().flatten() { - orig_deps.push(( - platform.dependencies.as_ref(), - vec!["target", name, DepKind::Normal.kind_table()], - )); - orig_deps.push(( - platform.build_dependencies.as_ref(), - vec!["target", name, DepKind::Normal.kind_table()], - )); - } + let group = + if let Some(contents) = contents + && let Some(document) = document + { + let feature_span = + get_key_value_span(&document, &["features", missing_dep.feature.as_str()]).unwrap(); + + let snippet = Snippet::source(contents) + .path(manifest_path) + .annotation(AnnotationKind::Primary.span(feature_span.value)); + + if missing_dep.weak_optional { + let mut orig_deps = vec![ + ( + orig_toml.dependencies.as_ref(), + vec![DepKind::Normal.kind_table()], + ), + ( + orig_toml.build_dependencies.as_ref(), + vec![DepKind::Build.kind_table()], + ), + ]; + for (name, platform) in orig_toml.target.iter().flatten() { + orig_deps.push(( + platform.dependencies.as_ref(), + vec!["target", name, DepKind::Normal.kind_table()], + )); + orig_deps.push(( + platform.build_dependencies.as_ref(), + vec!["target", name, DepKind::Normal.kind_table()], + )); + } - if let Some((_, toml_path)) = orig_deps.iter().find(|(deps, _)| { - if let Some(deps) = deps { - deps.keys().any(|p| *p.as_str() == *dep_name) + if let Some((_, toml_path)) = orig_deps.iter().find(|(deps, _)| { + if let Some(deps) = deps { + deps.keys().any(|p| *p.as_str() == *dep_name) + } else { + false + } + }) { + let toml_path = toml_path + .iter() + .map(|s| *s) + .chain(std::iter::once(dep_name.as_str())) + .collect::>(); + let dep_span = get_key_value_span(&document, &toml_path).unwrap(); + + group + .element(snippet.annotation( + AnnotationKind::Context.span(dep_span.key).label(info_label), + )) + .element(Level::HELP.message(help)) + } else { + group.element(snippet) + } } else { - false + group.element(snippet) } - }) { - let toml_path = toml_path - .iter() - .map(|s| *s) - .chain(std::iter::once(dep_name.as_str())) - .collect::>(); - let dep_span = get_key_value_span(&document, &toml_path).unwrap(); - - group - .element( - snippet - .annotation(AnnotationKind::Context.span(dep_span.key).label(info_label)), - ) - .element(Level::HELP.message(help)) } else { - group.element(snippet) - } - } else { - group.element(snippet) - }; + group + }; if let Err(err) = gctx.shell().print_report(&[group], true) { return Err(err.into()); @@ -1955,8 +1965,8 @@ fn missing_dep_diagnostic( } fn to_virtual_manifest( - contents: String, - document: toml::Spanned>, + contents: Option, + document: Option>>, original_toml: manifest::TomlManifest, normalized_toml: manifest::TomlManifest, features: Features, @@ -1997,9 +2007,9 @@ fn to_virtual_manifest( bail!("virtual manifests must be configured with [workspace]"); } let manifest = VirtualManifest::new( - Rc::new(contents), - Rc::new(document), - Rc::new(original_toml), + contents.map(Rc::new), + document.map(Rc::new), + Some(Rc::new(original_toml)), Rc::new(normalized_toml), replace, patch, @@ -2008,7 +2018,9 @@ fn to_virtual_manifest( resolve_behavior, ); - warn_on_unused(&manifest.original_toml()._unused_keys, warnings); + if let Some(original_toml) = manifest.original_toml() { + warn_on_unused(&original_toml._unused_keys, warnings); + } Ok(manifest) } @@ -2938,8 +2950,8 @@ pub fn prepare_for_publish( let mut errors = Default::default(); let gctx = ws.gctx(); let manifest = to_real_manifest( - contents.to_owned(), - document.clone(), + contents.map(|c| c.to_owned()), + document.cloned(), original_toml, normalized_toml, features,