Fix crate-name import resolution for bin+lib crates
Register the Cargo package name (normalized - -> _) as an alias for
src/lib.rs in the resolver, so 'use <crate>::{...}' in src/main.rs
resolves to src/lib.rs. Adds rustdemo/Cargo.toml fixture and test
coverage; updates blast-radius test for the new transitive edge.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
1 parent
0bb09da454
commit
6875998ab6
4 files changed
+64
-5
No files matched your search
+12
-1
@@ -294,7 +294,7 @@ fn clean(target: &str) -> Option<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Resolver {
|
impl Resolver {
|
||||||
pub fn build(files: Vec<(String, i64)>) -> Self {
|
pub fn build(files: Vec<(String, i64)>, crate_name: Option<&str>) -> Self {
|
||||||
let mut by_path = HashMap::new();
|
let mut by_path = HashMap::new();
|
||||||
let mut by_name = HashMap::new();
|
let mut by_name = HashMap::new();
|
||||||
let mut by_stem = HashMap::new();
|
let mut by_stem = HashMap::new();
|
||||||
@@ -308,6 +308,17 @@ impl Resolver {
|
|||||||
.unwrap_or(name);
|
.unwrap_or(name);
|
||||||
by_stem.entry(stem).or_insert(id);
|
by_stem.entry(stem).or_insert(id);
|
||||||
}
|
}
|
||||||
|
// `use <crate>::…` names the crate's own lib root, which always lives
|
||||||
|
// at src/lib.rs — there is no `<crate>.rs` file. Register the package
|
||||||
|
// name as an alias so bin→lib edges resolve. Workspaces (no [package]
|
||||||
|
// name) are skipped.
|
||||||
|
if let Some(name) = crate_name.filter(|n| !n.is_empty())
|
||||||
|
&& let Some(id) = by_path.get("src/lib.rs").copied()
|
||||||
|
{
|
||||||
|
by_path.insert(name.to_string(), id);
|
||||||
|
by_name.entry(name.to_string()).or_insert(id);
|
||||||
|
by_stem.entry(name.to_string()).or_insert(id);
|
||||||
|
}
|
||||||
Resolver {
|
Resolver {
|
||||||
by_path,
|
by_path,
|
||||||
by_name,
|
by_name,
|
||||||
|
|||||||
+28
-2
@@ -18,6 +18,30 @@ pub struct IndexStats {
|
|||||||
pub imports: i64,
|
pub imports: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read the `[package] name` from `Cargo.toml`, normalized to the crate
|
||||||
|
/// identifier (`-` → `_`) used in `use <crate>::…`.
|
||||||
|
fn read_crate_name(project: &Path) -> Option<String> {
|
||||||
|
let toml = std::fs::read_to_string(project.join("Cargo.toml")).ok()?;
|
||||||
|
let mut in_package = false;
|
||||||
|
for line in toml.lines() {
|
||||||
|
let l = line.trim();
|
||||||
|
if l.starts_with('[') {
|
||||||
|
in_package = l == "[package]";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if in_package
|
||||||
|
&& let Some(v) = l.strip_prefix("name").map(str::trim)
|
||||||
|
&& let Some(v) = v.strip_prefix('=').map(str::trim)
|
||||||
|
{
|
||||||
|
let name = v.trim_matches('"');
|
||||||
|
if !name.is_empty() {
|
||||||
|
return Some(name.replace('-', "_"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// (Re)index a project. `recreate` drops any existing index first.
|
/// (Re)index a project. `recreate` drops any existing index first.
|
||||||
pub fn run(project: &Path, db_path: &Path, recreate: bool) -> Result<IndexStats> {
|
pub fn run(project: &Path, db_path: &Path, recreate: bool) -> Result<IndexStats> {
|
||||||
if recreate && db_path.exists() {
|
if recreate && db_path.exists() {
|
||||||
@@ -83,8 +107,10 @@ pub fn run(project: &Path, db_path: &Path, recreate: bool) -> Result<IndexStats>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let resolver =
|
let resolver = imports::Resolver::build(
|
||||||
imports::Resolver::build(file_ids.iter().map(|(k, v)| (k.clone(), *v)).collect());
|
file_ids.iter().map(|(k, v)| (k.clone(), *v)).collect(),
|
||||||
|
read_crate_name(project).as_deref(),
|
||||||
|
);
|
||||||
|
|
||||||
for f in &changed {
|
for f in &changed {
|
||||||
let fid = file_ids[&f.rel];
|
let fid = file_ids[&f.rel];
|
||||||
|
|||||||
+20
-2
@@ -90,6 +90,22 @@ fn rust_index_search_and_dead() {
|
|||||||
"source contains function body"
|
"source contains function body"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// `use rustdemo::add` in main.rs resolves via the package-name alias.
|
||||||
|
let importers = run_json(&[
|
||||||
|
"--project",
|
||||||
|
fx.to_str().unwrap(),
|
||||||
|
"find",
|
||||||
|
"importers",
|
||||||
|
"src/lib.rs",
|
||||||
|
]);
|
||||||
|
let names: Vec<&str> = importers
|
||||||
|
.as_array()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.as_str().unwrap())
|
||||||
|
.collect();
|
||||||
|
assert!(names.contains(&"src/main.rs"), "main.rs imports lib.rs");
|
||||||
|
|
||||||
// dead.rs is flagged; entry points lib.rs/main.rs are not.
|
// dead.rs is flagged; entry points lib.rs/main.rs are not.
|
||||||
let dead = run_json(&["--project", fx.to_str().unwrap(), "find", "dead"]);
|
let dead = run_json(&["--project", fx.to_str().unwrap(), "find", "dead"]);
|
||||||
let paths: Vec<&str> = dead["files"]
|
let paths: Vec<&str> = dead["files"]
|
||||||
@@ -118,7 +134,7 @@ fn inspect_blast_radius_finds_affected_files() {
|
|||||||
"blast-radius",
|
"blast-radius",
|
||||||
"src/util.rs",
|
"src/util.rs",
|
||||||
]);
|
]);
|
||||||
assert_eq!(blast["count"], 1);
|
assert_eq!(blast["count"], 2);
|
||||||
assert_eq!(blast["file"], "src/util.rs");
|
assert_eq!(blast["file"], "src/util.rs");
|
||||||
let affected: Vec<&str> = blast["affected"]
|
let affected: Vec<&str> = blast["affected"]
|
||||||
.as_array()
|
.as_array()
|
||||||
@@ -126,7 +142,9 @@ fn inspect_blast_radius_finds_affected_files() {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|f| f["path"].as_str().unwrap())
|
.map(|f| f["path"].as_str().unwrap())
|
||||||
.collect();
|
.collect();
|
||||||
assert_eq!(affected, ["src/lib.rs"], "lib.rs imports util.rs");
|
// lib.rs imports util.rs directly; main.rs reaches it via the crate name.
|
||||||
|
assert!(affected.contains(&"src/lib.rs"), "lib.rs imports util.rs");
|
||||||
|
assert!(affected.contains(&"src/main.rs"), "main.rs → lib.rs → util.rs");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
[package]
|
||||||
|
name = "rustdemo"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
Reference in new issue
Block a user