code-moniker-workspace 0.7.1

Workspace model, ports, snapshots, linkage, and change analysis for code-moniker.
Documentation
use code_moniker_core::core::moniker::Moniker;
use code_moniker_core::lang::Lang;
use code_moniker_core::lang::build_manifest::Manifest;
use rustc_hash::FxHashSet;

use crate::linkage::binding::ReferenceLinkageDecision;
use crate::linkage::catalog::LinkageCandidate;
use crate::linkage::catalog::LinkageQuery;
use crate::snapshot::{RecordTable, ReferenceId, ReferenceRecord};
use crate::source::CodeIndexMaterial;

mod c;
mod csharp;
mod go;
mod java;
mod python;
mod rust;
mod selection;
mod sql;
mod ts;

pub(in crate::linkage) use c::{
	CIncludeVisibility, classify_c_preprocessor_tokens, classify_c_unindexed_external_dependencies,
	refine_c_include_visibility,
};
pub(in crate::linkage) use python::binding_invalidation_sources;
pub(in crate::linkage) use python::{BindingTarget, PythonBindings};
pub(in crate::linkage) use selection::{
	confirm_name_match_targets, global_resolution_evidence, local_resolution_evidence,
	prefer_concrete_definitions,
};

pub(super) fn matches_candidate(
	query: &LinkageQuery<'_>,
	candidate: &LinkageCandidate<'_>,
) -> bool {
	let Some(source) = query.material.files.get(query.source_file) else {
		return false;
	};
	let Some(target) = query.material.files.get(candidate.source_file) else {
		return false;
	};
	if source.lang != target.lang {
		return false;
	}
	match source.lang {
		Lang::Java => java::matches(query, candidate),
		Lang::Python => python::matches(query, candidate),
		Lang::Rs => rust::matches(query, candidate),
		Lang::Ts => ts::matches(query, candidate),
		Lang::Go => go::matches(query, candidate),
		Lang::C => c::matches(query, candidate),
		Lang::Cs => csharp::matches(query, candidate),
		Lang::Sql => sql::matches(query, candidate),
	}
}

fn generic_matches(query: &LinkageQuery<'_>, candidate: &LinkageCandidate<'_>) -> bool {
	candidate.moniker.bind_match(query.target) || query.target.bind_match(candidate.moniker)
}

pub(super) fn sql_call_has_strong_evidence(query: &LinkageQuery<'_>) -> bool {
	sql::call_has_strong_evidence(query)
}

pub(super) fn manifest_for_lang(lang: Lang) -> Option<Manifest> {
	match lang {
		Lang::Ts => Some(Manifest::PackageJson),
		Lang::Rs => Some(Manifest::Cargo),
		Lang::Java => Some(Manifest::PomXml),
		Lang::Python => Some(Manifest::Pyproject),
		Lang::Go => Some(Manifest::GoMod),
		Lang::Cs => Some(Manifest::Csproj),
		Lang::C | Lang::Sql => None,
	}
}

pub(super) fn package_prefix_for_target(lang: Lang, target: &Moniker) -> Option<String> {
	match lang {
		Lang::Java => java::package_prefix(target),
		Lang::Ts => ts::package_prefix(target),
		_ => None,
	}
}

pub(super) fn source_declares_external_package(
	lang: Lang,
	manifest: Manifest,
	deps: &FxHashSet<String>,
	package_prefix: &str,
	query_confidence: Option<&str>,
	workspace_declares_package: impl Fn(&str) -> bool,
) -> bool {
	match lang {
		Lang::Java => java::source_declares_external_package(
			manifest,
			deps,
			package_prefix,
			query_confidence,
			workspace_declares_package,
		),
		Lang::Ts => ts::source_declares_external_package(
			manifest,
			deps,
			package_prefix,
			query_confidence,
			workspace_declares_package,
		),
		_ => false,
	}
}

pub(super) fn proc_macro_annotation(query: &LinkageQuery<'_>) -> bool {
	rust::proc_macro_annotation(query)
}

pub(super) fn rust_external_crate_target_matches_def(
	query: &LinkageQuery<'_>,
	candidate: &LinkageCandidate<'_>,
	lib_path: &std::path::Path,
) -> bool {
	rust::external_crate_target_matches_def(query, candidate, lib_path)
}

pub(super) fn rust_sdk_method_fallback(query: &LinkageQuery<'_>) -> Option<Moniker> {
	rust::sdk_method_fallback(query)
}

pub(super) fn classify_open_references(
	material: &CodeIndexMaterial,
	decisions: &mut [ReferenceLinkageDecision],
	references: &RecordTable<ReferenceRecord>,
	changed_references: Option<&FxHashSet<ReferenceId>>,
) {
	for decision in decisions {
		let Some(reference_idx) = decision.refinement_pending_reference_idx() else {
			continue;
		};
		if changed_references.is_some_and(|changed| !changed.contains(decision.reference())) {
			continue;
		}
		let reference = &references[reference_idx];
		match reference_language(material, reference) {
			Some(Lang::Python) => {
				python::classify_open_reference(material, decision, reference_idx, reference)
			}
			Some(Lang::Cs) => {
				csharp::classify_open_reference(material, decision, reference_idx, reference)
			}
			Some(Lang::Sql) => sql::classify_open_reference(decision, reference_idx, reference),
			_ => {}
		}
	}
}

pub(super) fn refine_external_reexports(
	material: &CodeIndexMaterial,
	decisions: &mut [ReferenceLinkageDecision],
	references: &RecordTable<ReferenceRecord>,
	changed_references: Option<&FxHashSet<ReferenceId>>,
	decision_indices: &[usize],
) {
	ts::refine_external_reexports(
		material,
		decisions,
		references,
		changed_references,
		decision_indices,
	);
}

pub(super) fn classify_runtime_imports(
	material: &CodeIndexMaterial,
	decisions: &mut [ReferenceLinkageDecision],
	references: &RecordTable<ReferenceRecord>,
	changed_references: Option<&FxHashSet<ReferenceId>>,
	decision_indices: &[usize],
) {
	python::classify_runtime_imports(
		material,
		decisions,
		references,
		changed_references,
		decision_indices,
	);
}

fn reference_language(material: &CodeIndexMaterial, reference: &ReferenceRecord) -> Option<Lang> {
	material
		.symbol_moniker(&reference.source_symbol)
		.and_then(|source| {
			source
				.as_view()
				.segments()
				.find(|segment| segment.kind == code_moniker_core::lang::kinds::LANG)
				.and_then(|segment| std::str::from_utf8(segment.name).ok())
				.and_then(Lang::from_tag)
		})
}

fn external_target_shape(target: &Moniker) -> bool {
	target.as_view().segments().next().is_some_and(|segment| {
		matches!(
			segment.kind,
			code_moniker_core::lang::kinds::EXTERNAL_PKG | code_moniker_core::lang::kinds::SDK
		)
	})
}