|  | 
| 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 |  | -use annotate_snippets::{AnnotationKind, Group, Level, Snippet}; | 
| 4 |  | -use cargo_util_schemas::manifest::{TomlLintLevel, TomlToolLints}; | 
|  | 3 | +use annotate_snippets::{AnnotationKind, Group, Level, Patch, Snippet}; | 
|  | 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,158 @@ 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(( | 
|  | 537 | +                    vec!["profile", profile_name.as_str(), "hint-mostly-unused"], | 
|  | 538 | +                    true, | 
|  | 539 | +                )); | 
|  | 540 | +            } | 
|  | 541 | + | 
|  | 542 | +            if let Some(build_override) = &top_level_profile.build_override | 
|  | 543 | +                && let Some(true) = build_override.hint_mostly_unused | 
|  | 544 | +            { | 
|  | 545 | +                paths.push(( | 
|  | 546 | +                    vec![ | 
|  | 547 | +                        "profile", | 
|  | 548 | +                        profile_name.as_str(), | 
|  | 549 | +                        "build-override", | 
|  | 550 | +                        "hint-mostly-unused", | 
|  | 551 | +                    ], | 
|  | 552 | +                    false, | 
|  | 553 | +                )); | 
|  | 554 | +            } | 
|  | 555 | + | 
|  | 556 | +            if let Some(packages) = &top_level_profile.package | 
|  | 557 | +                && let Some(profile) = packages.get(&ProfilePackageSpec::All) | 
|  | 558 | +                && let Some(true) = profile.hint_mostly_unused | 
|  | 559 | +            { | 
|  | 560 | +                paths.push(( | 
|  | 561 | +                    vec![ | 
|  | 562 | +                        "profile", | 
|  | 563 | +                        profile_name.as_str(), | 
|  | 564 | +                        "package", | 
|  | 565 | +                        "*", | 
|  | 566 | +                        "hint-mostly-unused", | 
|  | 567 | +                    ], | 
|  | 568 | +                    false, | 
|  | 569 | +                )); | 
|  | 570 | +            } | 
|  | 571 | +        } | 
|  | 572 | +    } | 
|  | 573 | + | 
|  | 574 | +    for (i, (path, show_per_pkg_suggestion)) in paths.iter().enumerate() { | 
|  | 575 | +        if lint_level.is_error() { | 
|  | 576 | +            *error_count += 1; | 
|  | 577 | +        } | 
|  | 578 | +        let title = "`hint-mostly-unused` is being blanket applied to all dependencies"; | 
|  | 579 | +        let help_txt = | 
|  | 580 | +            "scope `hint-mostly-unused` to specific packages with a lot of unused object code"; | 
|  | 581 | +        if let (Some(span), Some(table_span)) = ( | 
|  | 582 | +            get_key_value_span(maybe_pkg.document(), &path), | 
|  | 583 | +            get_key_value_span(maybe_pkg.document(), &path[..path.len() - 1]), | 
|  | 584 | +        ) { | 
|  | 585 | +            let mut report = Vec::new(); | 
|  | 586 | +            let mut primary_group = level.clone().primary_title(title).element( | 
|  | 587 | +                Snippet::source(maybe_pkg.contents()) | 
|  | 588 | +                    .path(&manifest_path) | 
|  | 589 | +                    .annotation( | 
|  | 590 | +                        AnnotationKind::Primary.span(table_span.key.start..table_span.key.end), | 
|  | 591 | +                    ) | 
|  | 592 | +                    .annotation(AnnotationKind::Context.span(span.key.start..span.value.end)), | 
|  | 593 | +            ); | 
|  | 594 | + | 
|  | 595 | +            if *show_per_pkg_suggestion { | 
|  | 596 | +                report.push( | 
|  | 597 | +                    Level::HELP.secondary_title(help_txt).element( | 
|  | 598 | +                        Snippet::source(maybe_pkg.contents()) | 
|  | 599 | +                            .path(&manifest_path) | 
|  | 600 | +                            .patch(Patch::new( | 
|  | 601 | +                                table_span.key.end..table_span.key.end, | 
|  | 602 | +                                ".package.<pkg_name>", | 
|  | 603 | +                            )), | 
|  | 604 | +                    ), | 
|  | 605 | +                ); | 
|  | 606 | +            } else { | 
|  | 607 | +                primary_group = primary_group.element(Level::HELP.message(help_txt)); | 
|  | 608 | +            } | 
|  | 609 | + | 
|  | 610 | +            if i == 0 { | 
|  | 611 | +                primary_group = | 
|  | 612 | +                    primary_group | 
|  | 613 | +                        .element(Level::NOTE.message( | 
|  | 614 | +                            BLANKET_HINT_MOSTLY_UNUSED.emitted_source(lint_level, reason), | 
|  | 615 | +                        )); | 
|  | 616 | +            } | 
|  | 617 | + | 
|  | 618 | +            // The primary group should always be first | 
|  | 619 | +            report.insert(0, primary_group); | 
|  | 620 | + | 
|  | 621 | +            gctx.shell().print_report(&report, lint_level.force())?; | 
|  | 622 | +        } | 
|  | 623 | +    } | 
|  | 624 | + | 
|  | 625 | +    Ok(()) | 
|  | 626 | +} | 
|  | 627 | + | 
| 476 | 628 | const UNKNOWN_LINTS: Lint = Lint { | 
| 477 | 629 |     name: "unknown_lints", | 
| 478 | 630 |     desc: "unknown lint", | 
|  | 
0 commit comments