Skip to main content

vulnerability_keys

Function vulnerability_keys 

Source
pub fn vulnerability_keys(
    parse_result: &dyn ParseResult,
    resolved: &HashMap<PackageName, ConcreteVersion>,
    formatter: &dyn EcosystemFormatter,
    ecosystem: EcosystemId,
) -> HashMap<Range, String>
Expand description

Computes the VulnerabilityMap key each occurrence in parse_result should be scanned/looked-up under.

Keyed by Dependency::name_range — unique per occurrence within one document, so callers holding a specific dep (not just its name) can look their own key up directly.

Normally an occurrence’s key is just its normalized name (the common case, and the only form most VulnerabilityMap test fixtures use). When two or more occurrences of the same name resolve to different signatures — e.g. the same crate under [dependencies] and [dev-dependencies], or multiple [target.'cfg(...)'.dependencies] blocks (#394), pinned to different versions, or mixing a registry source with a git/path fork — each such occurrence’s key is instead qualified with a signature specific to it, so their OSV results can never collide in the shared map. Occurrences that share both a name and an identical signature (registry-source, same in-use version) intentionally keep the plain, shared key and get scanned once: the OSV result would be identical either way, so collapsing them is a dedup, not a gap.

Every caller that builds or looks up a VulnerabilityMap entry for a specific dependency occurrence — deps-lsp’s build_scan_targets, and the vulnerability lookups in generate_diagnostics_from_cache, generate_hover, and generate_code_actions — must go through this function so key construction never drifts out of sync between producer and consumer. A caller with no EcosystemId to give (most test fixtures) skips this and falls back to the plain normalized name, which still finds any entry a test inserted under that name directly.

§Examples

use deps_core::lsp_helpers::{
    DiagnosticMessages, DiagnosticPolicy, OsvNaming, PackageNaming, PackageRendering,
    RequirementResolution, SourcePolicy,
};
use deps_core::osv::vulnerability_keys;
use deps_core::{ConcreteVersion, Dependency, EcosystemId, PackageName, ParseResult, VersionReq};
use std::any::Any;
use std::collections::HashMap;
use tower_lsp_server::ls_types::{Position, Range, Uri};

struct SimpleDep {
    name: PackageName,
    version_req: Option<VersionReq>,
    name_range: Range,
}

impl Dependency for SimpleDep {
    fn name(&self) -> &PackageName {
        &self.name
    }
    fn name_range(&self) -> Range {
        self.name_range
    }
    fn version_requirement(&self) -> Option<&VersionReq> {
        self.version_req.as_ref()
    }
    fn version_range(&self) -> Option<Range> {
        None
    }
    fn source(&self) -> deps_core::parser::DependencySource {
        deps_core::parser::DependencySource::Registry
    }
    fn as_any(&self) -> &dyn Any {
        self
    }
}

struct SimpleParseResult {
    deps: Vec<SimpleDep>,
    uri: Uri,
}

impl ParseResult for SimpleParseResult {
    fn dependencies(&self) -> Vec<&dyn Dependency> {
        self.deps.iter().map(|d| d as &dyn Dependency).collect()
    }
    fn workspace_root(&self) -> Option<&std::path::Path> {
        None
    }
    fn uri(&self) -> &Uri {
        &self.uri
    }
    fn as_any(&self) -> &dyn Any {
        self
    }
}

struct SimpleFormatter;
impl PackageNaming for SimpleFormatter {}
impl PackageRendering for SimpleFormatter {
    fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String {
        version.to_string()
    }
    fn package_url(&self, name: &PackageName) -> String {
        name.to_string()
    }
}
impl RequirementResolution for SimpleFormatter {}
impl DiagnosticMessages for SimpleFormatter {}
impl DiagnosticPolicy for SimpleFormatter {}
impl SourcePolicy for SimpleFormatter {}
impl OsvNaming for SimpleFormatter {}

// `time` declared twice, pinned to two different versions.
let parse_result = SimpleParseResult {
    deps: vec![
        SimpleDep {
            name: PackageName::new("time"),
            version_req: Some(VersionReq::new("=0.1.43")),
            name_range: Range::new(Position::new(0, 0), Position::new(0, 4)),
        },
        SimpleDep {
            name: PackageName::new("time"),
            version_req: Some(VersionReq::new("=0.1.44")),
            name_range: Range::new(Position::new(3, 0), Position::new(3, 4)),
        },
    ],
    uri: deps_core::test_util::test_uri("/test/Cargo.toml"),
};
let resolved: HashMap<PackageName, ConcreteVersion> = HashMap::new();

let keys = vulnerability_keys(&parse_result, &resolved, &SimpleFormatter, EcosystemId::Cargo);
let deps = parse_result.dependencies();
let key0 = keys.get(&deps[0].name_range()).unwrap();
let key1 = keys.get(&deps[1].name_range()).unwrap();
assert_ne!(key0, key1, "differently-pinned occurrences of one name get distinct keys");