cargo/diagnostics/rules/
min_opt_level_hint.rs1use std::path::Path;
2
3use cargo_util_terminal::report::AnnotationKind;
4use cargo_util_terminal::report::Group;
5use cargo_util_terminal::report::Level;
6use cargo_util_terminal::report::Origin;
7use cargo_util_terminal::report::Snippet;
8
9use crate::CargoResult;
10use crate::GlobalContext;
11use crate::diagnostics::ScopedDiagnosticStats;
12use crate::diagnostics::TomlSpan;
13use crate::diagnostics::get_key_value_span;
14use crate::diagnostics::workspace_rel_path;
15use crate::workspace::Package;
16use crate::workspace::Workspace;
17use crate::workspace::profiles::{MinOptLevelHintError, parse_min_opt_level_hint};
18
19#[tracing::instrument(skip_all)]
21pub(crate) fn diagnose_package(
22 ws: &Workspace<'_>,
23 pkg: &Package,
24 path: &Path,
25 pkg_stats: &mut ScopedDiagnosticStats<'_>,
26 gctx: &GlobalContext,
27) -> CargoResult<()> {
28 let manifest_path = workspace_rel_path(ws, path);
29 let min_opt_level = match parse_min_opt_level_hint(
30 pkg.hints().and_then(|hints| hints.min_opt_level.as_ref()),
31 ) {
32 Ok(level) => level,
33 Err(err) => {
34 let (title, label) = match err {
35 MinOptLevelHintError::OutOfRange { level, expected } => (
36 format!("ignoring unsupported value `{level}` for `hints.min-opt-level`"),
37 format!(
38 "expected an integer from {} to {}",
39 expected.start(),
40 expected.end()
41 ),
42 ),
43 MinOptLevelHintError::WrongType(value_type) => (
44 format!(
45 "ignoring unsupported value type `{value_type}` for `hints.min-opt-level`"
46 ),
47 "expected an integer".to_owned(),
48 ),
49 };
50 let group = Group::with_title(Level::WARNING.primary_title(title));
51 let group = match hint_span(pkg) {
52 Some((contents, span)) => group.element(
53 Snippet::source(contents)
54 .path(&manifest_path)
55 .annotation(AnnotationKind::Primary.span(span.value).label(label)),
56 ),
57 None => group.element(Origin::path(&manifest_path)),
58 };
59 pkg_stats.record_warning();
60 gctx.shell().print_report(&[group], false)?;
61 None
62 }
63 };
64
65 if matches!(min_opt_level, Some(1..)) && !gctx.cli_unstable().hint_min_opt_level {
66 let group =
67 Group::with_title(Level::WARNING.primary_title("ignoring `hints.min-opt-level`"));
68 let group = match hint_span(pkg) {
69 Some((contents, span)) => group.element(
70 Snippet::source(contents)
71 .path(&manifest_path)
72 .annotation(AnnotationKind::Primary.span(span.key.start..span.value.end)),
73 ),
74 None => group.element(Origin::path(&manifest_path)),
75 };
76 let group = group.element(Level::HELP.message("pass `-Zhint-min-opt-level` to enable it"));
77 pkg_stats.record_warning();
78 gctx.shell().print_report(&[group], false)?;
79 }
80
81 Ok(())
82}
83
84fn hint_span(pkg: &Package) -> Option<(&str, TomlSpan)> {
86 let manifest = pkg.manifest();
87 let contents = manifest.contents()?;
88 let document = manifest.document()?;
89 let span = get_key_value_span(document, &["hints", "min-opt-level"])?;
90 Some((contents, span))
91}