Something went wrong. Try again.
Identities for entities did.bot
agent llm did
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205//! The questions the index exists to answer.
use anyhow::{Context, Result};use rusqlite::{params, Connection};use std::path::Path;
pub fn open(db_path: &Path) -> Result<Connection> { let conn = Connection::open(db_path).with_context(|| format!("opening {}", db_path.display()))?; conn.query_row("SELECT value FROM meta WHERE key = 'revision'", [], |r| { r.get::<_, String>(0) }) .with_context(|| format!("{} is not an xray index", db_path.display()))?; Ok(conn)}
/// A reference that counts as a use. A `pub use` re-export names an item/// without using it, so a crate that only re-exports something has not kept/// it alive.const LIVE_REF: &str = " SELECT r.* FROM ref r LEFT JOIN item f ON f.id = r.from_item WHERE f.kind IS NULL OR f.kind <> 'use'";
pub fn info(conn: &Connection) -> Result<()> { let mut stmt = conn.prepare("SELECT key, value FROM meta ORDER BY key")?; let rows = stmt.query_map([], |r| Ok((r.get::<_, String>(0)?, r.get::<_, String>(1)?)))?; for row in rows { let (k, v) = row?; println!("{k}\t{v}"); } for (label, sql) in [ ("items", "SELECT COUNT(*) FROM item"), ("refs", "SELECT COUNT(*) FROM ref"), ("crates", "SELECT COUNT(DISTINCT crate) FROM item"), ] { let n: i64 = conn.query_row(sql, [], |r| r.get(0))?; println!("{label}\t{n}"); } Ok(())}
/// Public items whose `pub` earns nothing: nothing outside the crate reaches/// them, and no test does either.pub fn dead_pub(conn: &Connection, krate: Option<&str>, all: bool) -> Result<()> { let sql = format!( " SELECT i.module_path || '::' || i.name AS path, i.kind, i.file, i.line_start, (SELECT COUNT(*) FROM ({LIVE_REF}) l WHERE l.to_item = i.id) AS n, (SELECT COUNT(DISTINCT l.file) FROM ({LIVE_REF}) l WHERE l.to_item = i.id AND l.file <> i.file) AS elsewhere FROM item i WHERE i.visibility = 'public' AND i.target_kind = 'lib' AND i.kind NOT IN ('use', 'module', 'extern_crate') AND (?1 OR i.exported = 1) AND (?2 IS NULL OR i.crate = ?2) AND NOT EXISTS ( SELECT 1 FROM ({LIVE_REF}) l WHERE l.to_item = i.id AND (l.crate <> i.crate OR l.target_kind NOT IN ('lib', 'bin') OR l.cfg_gated = 1) ) ORDER BY i.crate, i.file, i.line_start " ); let mut stmt = conn.prepare(&sql)?; let rows = stmt.query_map(params![all, krate], |r| { Ok(( r.get::<_, String>(0)?, r.get::<_, String>(1)?, r.get::<_, String>(2)?, r.get::<_, i64>(3)?, r.get::<_, i64>(4)?, r.get::<_, i64>(5)?, )) })?; let mut total = 0; for row in rows { let (path, kind, file, line, n, elsewhere) = row?; let verdict = match (n, elsewhere) { (0, _) => "unreferenced", (_, 0) => "file-local", _ => "crate-local", }; println!("{file}:{line}\t{kind}\t{verdict}\t{n} refs\t{path}"); total += 1; } eprintln!("{total} public items reach nothing outside their own crate"); Ok(())}
/// Every reference to an item, by full path or by any suffix of one.pub fn refs(conn: &Connection, path: &str) -> Result<()> { let mut stmt = conn.prepare( "SELECT id, module_path || '::' || name, kind, file, line_start FROM item WHERE module_path || '::' || name = ?1 OR module_path || '::' || name LIKE '%::' || ?1 ORDER BY file, line_start", )?; let found = stmt .query_map(params![path], |r| { Ok(( r.get::<_, i64>(0)?, r.get::<_, String>(1)?, r.get::<_, String>(2)?, r.get::<_, String>(3)?, r.get::<_, i64>(4)?, )) })? .collect::<rusqlite::Result<Vec<_>>>()?; if found.is_empty() { anyhow::bail!("no item matches {path}"); } for (id, full, kind, file, line) in found { println!("{kind} {full}\n defined at {file}:{line}"); let mut stmt = conn.prepare( "SELECT r.file, r.line, r.crate, r.target_kind, r.cfg_gated, CASE WHEN f.kind = 'use' THEN '(re-export)' ELSE COALESCE(f.module_path || '::' || f.name, '') END FROM ref r LEFT JOIN item f ON f.id = r.from_item WHERE r.to_item = ?1 ORDER BY r.file, r.line", )?; let rows = stmt.query_map(params![id], |r| { Ok(( r.get::<_, String>(0)?, r.get::<_, i64>(1)?, r.get::<_, String>(2)?, r.get::<_, String>(3)?, r.get::<_, i64>(4)?, r.get::<_, String>(5)?, )) })?; let mut n = 0; for row in rows { let (file, line, krate, target, gated, from) = row?; let tag = if gated == 1 { " [cfg-gated]" } else { "" }; println!(" {file}:{line}\t{krate} {target}{tag}\t{from}"); n += 1; } println!(" {n} references"); } Ok(())}
/// Declared workspace dependencies, each with the number of item-level/// references that actually cross that edge.pub fn crate_edges(conn: &Connection) -> Result<()> { let mut stmt = conn.prepare( " SELECT d.from_crate, d.to_crate, d.kind, (SELECT COUNT(*) FROM ref r JOIN item i ON i.id = r.to_item WHERE r.crate = d.from_crate AND i.crate = d.to_crate) AS n FROM dep d ORDER BY d.from_crate, d.to_crate ", )?; let rows = stmt.query_map([], |r| { Ok(( r.get::<_, String>(0)?, r.get::<_, String>(1)?, r.get::<_, String>(2)?, r.get::<_, i64>(3)?, )) })?; let mut unused = 0; for row in rows { let (from, to, kind, n) = row?; if n == 0 { unused += 1; } println!("{from}\t{to}\t{kind}\t{n}"); } eprintln!("{unused} declared dependencies carry no item-level reference"); Ok(())}
/// Every item in a file, with the span it occupies.pub fn file_items(conn: &Connection, file: &str) -> Result<()> { let mut stmt = conn.prepare( "SELECT line_start, line_end, kind, visibility, module_path || '::' || name, (SELECT COUNT(*) FROM ref r WHERE r.to_item = item.id) FROM item WHERE file = ?1 OR file LIKE '%' || ?1 ORDER BY line_start", )?; let rows = stmt.query_map(params![file], |r| { Ok(( r.get::<_, i64>(0)?, r.get::<_, i64>(1)?, r.get::<_, String>(2)?, r.get::<_, String>(3)?, r.get::<_, String>(4)?, r.get::<_, i64>(5)?, )) })?; let mut n = 0; for row in rows { let (start, end, kind, vis, path, refs) = row?; println!("{start}-{end}\t{vis} {kind}\t{refs} refs\t{path}"); n += 1; } eprintln!("{n} items"); Ok(())}