|  | 
| 1 |  | -use crate::core::{Edition, Feature, Features, Manifest, Package}; | 
|  | 1 | +use crate::core::{Edition, Feature, Features, Manifest, MaybePackage, Package}; | 
| 2 | 2 | use crate::{CargoResult, GlobalContext}; | 
| 3 | 3 | use annotate_snippets::{AnnotationKind, Group, Level, Snippet}; | 
| 4 |  | -use cargo_util_schemas::manifest::{TomlLintLevel, TomlToolLints}; | 
|  | 4 | +use cargo_util_schemas::manifest::{ProfilePackageSpec, TomlLintLevel, TomlToolLints}; | 
| 5 | 5 | use pathdiff::diff_paths; | 
| 6 | 6 | use std::fmt::Display; | 
| 7 | 7 | use std::ops::Range; | 
| 8 | 8 | use std::path::Path; | 
| 9 | 9 | 
 | 
| 10 | 10 | const LINT_GROUPS: &[LintGroup] = &[TEST_DUMMY_UNSTABLE]; | 
| 11 |  | -pub const LINTS: &[Lint] = &[IM_A_TEAPOT, UNKNOWN_LINTS]; | 
|  | 11 | +pub const LINTS: &[Lint] = &[BLANKET_HINT_MOSTLY_UNUSED, IM_A_TEAPOT, UNKNOWN_LINTS]; | 
| 12 | 12 | 
 | 
| 13 | 13 | pub fn analyze_cargo_lints_table( | 
| 14 | 14 |     pkg: &Package, | 
| @@ -473,6 +473,126 @@ pub fn check_im_a_teapot( | 
| 473 | 473 |     Ok(()) | 
| 474 | 474 | } | 
| 475 | 475 | 
 | 
|  | 476 | +const BLANKET_HINT_MOSTLY_UNUSED: Lint = Lint { | 
|  | 477 | +    name: "blanket_hint_mostly_unused", | 
|  | 478 | +    desc: "blanket_hint_mostly_unused lint", | 
|  | 479 | +    groups: &[], | 
|  | 480 | +    default_level: LintLevel::Warn, | 
|  | 481 | +    edition_lint_opts: None, | 
|  | 482 | +    feature_gate: None, | 
|  | 483 | +    docs: Some( | 
|  | 484 | +        r#" | 
|  | 485 | +### What it does | 
|  | 486 | +Checks if `hint-mostly-unused` being applied to all dependencies. | 
|  | 487 | +
 | 
|  | 488 | +### Why it is bad | 
|  | 489 | +`hint-mostly-unused` indicates that most of a crate's API surface will go | 
|  | 490 | +unused by anything depending on it; this hint can speed up the build by | 
|  | 491 | +attempting to minimize compilation time for items that aren't used at all. | 
|  | 492 | +Misapplication to crates that don't fit that criteria will slow down the build | 
|  | 493 | +rather than speeding it up. It should be selectively applied to dependencies | 
|  | 494 | +that meet these criteria. Applying it globally is always a misapplication and | 
|  | 495 | +will likely slow down the build. | 
|  | 496 | +
 | 
|  | 497 | +### Example | 
|  | 498 | +```toml | 
|  | 499 | +[profile.dev.package."*"] | 
|  | 500 | +hint-mostly-unused = true | 
|  | 501 | +``` | 
|  | 502 | +
 | 
|  | 503 | +Should instead be: | 
|  | 504 | +```toml | 
|  | 505 | +[profile.dev.package.huge-mostly-unused-dependency] | 
|  | 506 | +hint-mostly-unused = true | 
|  | 507 | +``` | 
|  | 508 | +"#, | 
|  | 509 | +    ), | 
|  | 510 | +}; | 
|  | 511 | + | 
|  | 512 | +pub fn blanket_hint_mostly_unused( | 
|  | 513 | +    maybe_pkg: &MaybePackage, | 
|  | 514 | +    path: &Path, | 
|  | 515 | +    pkg_lints: &TomlToolLints, | 
|  | 516 | +    error_count: &mut usize, | 
|  | 517 | +    gctx: &GlobalContext, | 
|  | 518 | +) -> CargoResult<()> { | 
|  | 519 | +    let (lint_level, reason) = BLANKET_HINT_MOSTLY_UNUSED.level( | 
|  | 520 | +        pkg_lints, | 
|  | 521 | +        maybe_pkg.edition(), | 
|  | 522 | +        maybe_pkg.unstable_features(), | 
|  | 523 | +    ); | 
|  | 524 | + | 
|  | 525 | +    if lint_level == LintLevel::Allow { | 
|  | 526 | +        return Ok(()); | 
|  | 527 | +    } | 
|  | 528 | + | 
|  | 529 | +    let level = lint_level.to_diagnostic_level(); | 
|  | 530 | +    let manifest_path = rel_cwd_manifest_path(path, gctx); | 
|  | 531 | +    let mut paths = Vec::new(); | 
|  | 532 | + | 
|  | 533 | +    if let Some(profiles) = maybe_pkg.profiles() { | 
|  | 534 | +        for (profile_name, top_level_profile) in &profiles.0 { | 
|  | 535 | +            if let Some(true) = top_level_profile.hint_mostly_unused { | 
|  | 536 | +                paths.push(vec!["profile", profile_name.as_str(), "hint-mostly-unused"]); | 
|  | 537 | +            } | 
|  | 538 | + | 
|  | 539 | +            if let Some(build_override) = &top_level_profile.build_override | 
|  | 540 | +                && let Some(true) = build_override.hint_mostly_unused | 
|  | 541 | +            { | 
|  | 542 | +                paths.push(vec![ | 
|  | 543 | +                    "profile", | 
|  | 544 | +                    profile_name.as_str(), | 
|  | 545 | +                    "build-override", | 
|  | 546 | +                    "hint-mostly-unused", | 
|  | 547 | +                ]); | 
|  | 548 | +            } | 
|  | 549 | + | 
|  | 550 | +            if let Some(packages) = &top_level_profile.package | 
|  | 551 | +                && let Some(profile) = packages.get(&ProfilePackageSpec::All) | 
|  | 552 | +                && let Some(true) = profile.hint_mostly_unused | 
|  | 553 | +            { | 
|  | 554 | +                paths.push(vec![ | 
|  | 555 | +                    "profile", | 
|  | 556 | +                    profile_name.as_str(), | 
|  | 557 | +                    "package", | 
|  | 558 | +                    "*", | 
|  | 559 | +                    "hint-mostly-unused", | 
|  | 560 | +                ]); | 
|  | 561 | +            } | 
|  | 562 | +        } | 
|  | 563 | +    } | 
|  | 564 | + | 
|  | 565 | +    for (i, path) in paths.iter().enumerate() { | 
|  | 566 | +        if lint_level.is_error() { | 
|  | 567 | +            *error_count += 1; | 
|  | 568 | +        } | 
|  | 569 | +        let title = "`hint-mostly-unused` is being blanket applied to dependencies"; | 
|  | 570 | +        if let (Some(span), Some(table_span)) = ( | 
|  | 571 | +            get_key_value_span(maybe_pkg.document(), &path), | 
|  | 572 | +            get_key_value_span(maybe_pkg.document(), &path[..path.len() - 1]), | 
|  | 573 | +        ) { | 
|  | 574 | +            let mut group = level.clone().primary_title(title).element( | 
|  | 575 | +                Snippet::source(maybe_pkg.contents()) | 
|  | 576 | +                    .path(&manifest_path) | 
|  | 577 | +                    .annotation(AnnotationKind::Primary.span(span.key.start..span.value.end)) | 
|  | 578 | +                    .annotation(AnnotationKind::Visible.span(table_span.key)), | 
|  | 579 | +            ); | 
|  | 580 | + | 
|  | 581 | +            if i == 0 { | 
|  | 582 | +                group = | 
|  | 583 | +                    group | 
|  | 584 | +                        .element(Level::NOTE.message( | 
|  | 585 | +                            BLANKET_HINT_MOSTLY_UNUSED.emitted_source(lint_level, reason), | 
|  | 586 | +                        )); | 
|  | 587 | +            } | 
|  | 588 | + | 
|  | 589 | +            gctx.shell().print_report(&[group], lint_level.force())?; | 
|  | 590 | +        } | 
|  | 591 | +    } | 
|  | 592 | + | 
|  | 593 | +    Ok(()) | 
|  | 594 | +} | 
|  | 595 | + | 
| 476 | 596 | const UNKNOWN_LINTS: Lint = Lint { | 
| 477 | 597 |     name: "unknown_lints", | 
| 478 | 598 |     desc: "unknown lint", | 
|  | 
0 commit comments