weavatrix-clone 0.1.3

Evidence-first Type-1/2/3 code clone engine with deterministic families and bounded near-miss verification
Documentation
use super::detect::RegionKey;
use super::{BlockSource, BlockTokens};
use crate::cluster::pair_id;
use crate::model::{CloneEvidence, CloneKind, CloneLocation, ClonePair, Similarity, SourceSpan};

pub(super) fn region_pair(
    region: RegionKey,
    sources: &[BlockSource],
    tokens: &[BlockTokens],
    minimum: usize,
) -> ClonePair {
    let left = location(
        &sources[region.left_source],
        &tokens[region.left_source],
        region.left_start,
        region.length,
    );
    let right = location(
        &sources[region.right_source],
        &tokens[region.right_source],
        region.right_start,
        region.length,
    );
    ClonePair {
        id: pair_id(&left, &right),
        left,
        right,
        kind: CloneKind::Type1,
        similarity: Similarity::PERFECT,
        evidence: CloneEvidence {
            strict_equal: true,
            renamed_equal: true,
            shared_fingerprints: region.length.saturating_sub(minimum).saturating_add(1),
            fingerprint_jaccard: Similarity::PERFECT,
            fingerprint_containment: Similarity::PERFECT,
            edit_distance: 0,
            compared_tokens: region.length,
        },
    }
}

pub(super) fn line_count(span: SourceSpan) -> usize {
    usize::try_from(
        span.end_line
            .saturating_sub(span.start_line)
            .saturating_add(1),
    )
    .unwrap_or(usize::MAX)
}

fn location(
    source: &BlockSource,
    tokens: &BlockTokens,
    start: usize,
    length: usize,
) -> CloneLocation {
    let first = tokens.positions[start];
    let last = tokens.positions[start + length - 1];
    CloneLocation {
        fragment_id: format!("{}#tokens:{start}-{}", source.path, start + length),
        path: source.path.clone(),
        span: SourceSpan {
            start_byte: first.start_byte,
            end_byte: last.end_byte,
            start_line: first.start_line,
            end_line: last.end_line,
        },
    }
}