Repository navigation
Description
Track: feature-gap
Summary
polyscan builds no dependency graph for Rust. Dependency analysis covers Go and JavaScript/TypeScript, so a Rust crate gets no module graph, no cycle detection and no instability or distance metrics.
Rationale
The modules of one Rust crate may depend on each other in a cycle, which Go forbids between packages. A cycle does not break the build, but it ties the modules together: none of them can be moved into a separate crate, because the crate graph must stay acyclic, and that limits incremental and parallel builds. A dependency graph would show where a crate's layering has collapsed, which is the question the dependency dimension answers for Go and JavaScript.
Evidence
In EmbarkStudios/quilkin, the root crate (src/, about 105 module files) has 15 top-level modules, and 11 of them (alloc, cli, codec, components, config, filters, metrics, net, service, signal, tls) form one strongly connected component through crate:: paths. None of the edges below is test code.
| From | To |
|---|---|
src/cli.rs:132 pub service: crate::service::Service, |
src/service.rs:380 termination_timeout: Option<crate::cli::Duration> |
src/config.rs:77 crate::metrics::leader_election(is_leader) |
src/metrics.rs:581 icao: crate::config::IcaoCode |
src/config/filter.rs:1 use crate::filters::{CreationError, FilterChain, FilterInstance}; |
src/filters.rs:81 use crate::config::filter::Filter as FilterConfig; |
src/net/packet.rs:54 use crate::service::ALLOW_EMPTY_PACKETS_FLAG; |
src/service.rs:1246 crate::net::packet::spawn_receivers( |
polyscan reports no Rust module. Its only dependency module on this repository is one JavaScript file in docs/:
{"total_modules": 1, "nodes": ["docs/mermaid-init.js"], "total_cycles": 0}Repro
// src/lib.rs
pub mod config;
pub mod service;
// src/config.rs
pub struct Config {
pub port: u16,
}
pub fn build(s: &crate::service::Service) -> Config {
Config { port: s.port() }
}
// src/service.rs
pub struct Service {
port: u16,
}
impl Service {
pub fn port(&self) -> u16 {
self.port
}
pub fn reload(&self) -> crate::config::Config {
crate::config::build(self)
}
}With a Cargo.toml beside it, polyscan analyze --format json . prints "deps_enabled": false and no deps section, although config and service depend on each other.
Proposed change
For Rust, polyscan builds a module dependency graph from the mod tree of each crate and the use and qualified paths that name another module of the same workspace. It reports cycles, the longest chains, and instability and distance per module, as it does for Go packages, and test modules stay out of it. A child module that reaches its parent through super:: is idiomatic Rust, so the graph does not report a parent and its own child as a cycle; scoring the graph at the level of a crate's top-level modules is one way to achieve that.
Impact: med. Effort: medium. Confidence: high.
polyscan version 0.6.1.
Verification: survived refutation. No issue tracks Rust dependency analysis, all cited lines match, and a separate scan re-derived the same 11-module component. Impact was lowered from high because a module cycle inside a crate has no runtime cost; its cost is architectural.
Found via the polyscan-enhancement-audit skill in repo EmbarkStudios/quilkin@58f4f0b1b390a7c527cb0228c9267055f716d48f.
Want to work on this? Run polyscan on a project of your own first, and say in a comment which project you ran it on. See CONTRIBUTING.md, "Pull Requests".
Activity