Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/nornir

src/knowledge/scip.rs

//! RESOLVED knowledge map — the SCIP ROW MODEL and its id helpers.
//!
//! The `rust-analyzer scip` subprocess ingest that used to live here (spawn,
//! `index.scip` protobuf decode, retry/deadline/stderr digest) was removed with
//! Mímir v2 (PLAN-MIMIR-V2 §7.3a); the rustc-driver dump replaces it (lane 3).
//! What stays is the id scheme: the [`ScipRow`] / [`ScipScan`] PODs (lifted into
//! the edda `nornir-warehouse-trait` leaf and re-exported here) and the pure
//! def-site-key classifier.

// The RESOLVED-knowledge PODs live in the edda `nornir-warehouse-trait` leaf so
// the `Warehouse::load_latest_scip` trait surface can name them without pulling
// nornir. Re-exported so every `crate::knowledge::scip::{ScipScan, ScipRow}` call
// site is untouched.
pub use nornir_warehouse_trait::{ScipRow, ScipScan};

/// Is `symbol` a DEF-SITE KEY (`<workspace-relative file>#Lline:Ccol`, the id the
/// removed in-process rust-analyzer road synthesized) rather than a real,
/// globally-unique SCIP moniker?
///
/// PURE + unit-tested, because the two vocabularies are easy to confuse by eye
/// and a def-site key must never be joined across scans. A SCIP moniker is
/// either `local N` or `<scheme> <manager> <package> <version> <descriptors>`;
/// a def-site key is `file#Lline:Ccol` from a def's navigation range. The distinguishing
/// mark is the exact `#L<digits>:C<digits>` SUFFIX — a real moniker never ends in
/// one, and neither near-miss (`#L7`, `#Lx:C4`, `#L7:C`) is claimed.
///
/// The `file` half is workspace-RELATIVE, which is precisely why the key cannot
/// cross a scan boundary: every repo in the workspace has a `src/lib.rs`.
pub fn is_def_site_key(symbol: &str) -> bool {
    let Some((head, tail)) = symbol.rsplit_once("#L") else {
        return false;
    };
    if head.is_empty() {
        return false;
    }
    let Some((line, col)) = tail.split_once(":C") else {
        return false;
    };
    !line.is_empty()
        && !col.is_empty()
        && line.bytes().all(|b| b.is_ascii_digit())
        && col.bytes().all(|b| b.is_ascii_digit())
}

/// Is this scan keyed by def-site keys rather than real SCIP monikers?
///
/// Read off the DEFINITION rows, which is where the identity scheme is decided;
/// an empty scan is not def-site-keyed (there is nothing to refuse). Cheap enough
/// to call per scan — it stops at the first definition.
pub fn scan_is_def_site_keyed(scan: &ScipScan) -> bool {
    scan.rows
        .iter()
        .find(|r| r.is_definition)
        .is_some_and(|r| is_def_site_key(&r.symbol))
}

#[cfg(test)]
mod tests {
    use super::*;
    use chrono::Utc;
    use uuid::Uuid;

    /// A def-site-keyed row (not a SCIP moniker).
    fn def_site_row(
        symbol: &str,
        kind: &str,
        display_name: &str,
        file: &str,
        line: u32,
        enc: (u32, u32),
        is_definition: bool,
    ) -> ScipRow {
        ScipRow {
            symbol: symbol.to_string(),
            role: if is_definition { "definition" } else { "reference" }.to_string(),
            is_definition,
            display_name: display_name.to_string(),
            kind: kind.to_string(),
            file: file.to_string(),
            start_line: line,
            start_col: 4,
            enc_start_line: enc.0,
            enc_end_line: enc.1,
        }
    }

    /// Member `alpha`, def-site keyed. `run()` is callable and spans 10..20;
    /// `count` is a FIELD at `src/lib.rs#L7:C4`; line 14 inside `run()` reads it.
    fn alpha_in_process_scan() -> ScipScan {
        ScipScan {
            snapshot_id: Uuid::nil(),
            ts: Utc::now(),
            repo: "alpha".into(),
            git_sha: "alphasha".into(),
            rows: vec![
                def_site_row("src/lib.rs#L10:C4", "Function", "run", "src/lib.rs", 10, (10, 20), true),
                def_site_row("src/lib.rs#L7:C4", "Field", "count", "src/lib.rs", 7, (0, 0), true),
                // The read of `self.count` at line 14 — `refs_in_file` gives it the
                // FIELD's def-site key, an empty display_name and an empty kind.
                def_site_row("src/lib.rs#L7:C4", "", "", "src/lib.rs", 14, (0, 0), false),
            ],
        }
    }

    /// The classifier the refusal rests on, asserted on both vocabularies.
    #[test]
    fn def_site_key_classifier_separates_the_two_vocabularies() {
        // ra_ingest def-site keys.
        assert!(is_def_site_key("src/lib.rs#L7:C4"));
        assert!(is_def_site_key("crates/a/src/mod.rs#L1:C1"));
        assert!(is_def_site_key("a#L10:C20"));
        // Real SCIP monikers (and locals) are never mistaken for one.
        assert!(!is_def_site_key("rust-analyzer cargo demo_lib 0.1.0 helper()."));
        assert!(!is_def_site_key("local 3"));
        assert!(!is_def_site_key(""));
        // Near-misses stay OUT of the def-site bucket (they are not our key shape).
        assert!(!is_def_site_key("src/lib.rs#L7"));
        assert!(!is_def_site_key("src/lib.rs#Lx:C4"));
        assert!(!is_def_site_key("src/lib.rs#L7:C"));
    }

    /// A scan is classified by what its DEFINITIONS are keyed by.
    #[test]
    fn scan_provenance_is_read_off_the_definition_keys() {
        assert!(scan_is_def_site_keyed(&alpha_in_process_scan()));
        let mut lib = ScipScan::default();
        lib.rows.push(ScipRow {
            symbol: "rust-analyzer cargo demo_lib 0.1.0 helper().".into(),
            role: "definition".into(),
            is_definition: true,
            display_name: "helper".into(),
            kind: "Function".into(),
            file: "src/lib.rs".into(),
            start_line: 6,
            start_col: 7,
            enc_start_line: 6,
            enc_end_line: 10,
        });
        assert!(!scan_is_def_site_keyed(&lib));
        assert!(!scan_is_def_site_keyed(&ScipScan::default()));
    }
}