You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[BUG][auto] rust/rust-unimported-bare-name-resolved-tree-wide: a Send bound is counted as a dependency on the crate's own struct Send in an unrelated private module #215
A bare Rust type name that its file neither declares nor imports is resolved by looking it up across the whole tree. rustName in polyscan/internal/analysis/coupling.go returns the name unchanged when file.uses has no entry for it, and resolve then falls through byFileBare to byBare, which returns the single declaration of that name anywhere in the tree. A name that is neither local nor imported can only come from the prelude, a glob import or a macro, so the lookup is wrong whenever a crate declares a type with a prelude name: every Send bound in the crate is then counted as a dependency on that type. PR #214 made imported and path-qualified names resolve by their path; an unqualified name that no use binds still reaches the tree-wide lookup.
Checker and Worker have no dependency on a type of the tree. inner is a private module and neither item imports inner::Send, so Send can only be std::marker::Send.
On cfal/shoes, which declares pub struct Send in src/xhttp/h3.rs:152 behind a private mod h3;, 41 of the 513 listed Rust types carry Send in dependent_classes, 36 of them in files outside src/xhttp/ that cannot name h3::Send at all. Two risk levels change once the entry is removed.
Type
Use of Send
coupling_count
SaltChecker (src/shadowsocks/salt_checker.rs:3)
pub trait SaltChecker: Send + Sync + Debug
1, its only dependency
ProxyConnector (src/tcp/proxy_connector.rs:41)
trait bound
8 (high, 7 without it)
CarrierDialer (src/tcp/carrier_dialer.rs:18)
trait bound
4 (medium, 3 without it)
State (src/xhttp/server.rs:41)
impl FnOnce() + Send + 'static at line 638
23
A fix needs rustdeps.ParseUses to report the glob imports of a file, so that rustName can return false for an unimported bare name when the file has none, and the tree-wide lookup can be limited to the modules a glob names. ParseUses merges the uses of every scope, so a use super::* inside a #[cfg(test)] module would still count as a glob for the file.
polyscan version 0.6.0-10-g4b6a880
Priority P2: the trigger, a crate type named like a prelude item, is uncommon, but one such declaration mis-measures every Send bound in the crate.
Found via the FP-audit skill in repo cfal/shoes@1fac4c231c93f340f71c92bf04ea8e8ab1465877.
The same fallback also fires on two other kinds of bare name, found by the triage pass on cfal/shoes with an instrumented build:
The name of an associated type item is captured as a reference: type Send = UdpSender; and type Recv = UdpReceiver; at src/wireguard/io.rs:133-134 resolve to src/xhttp/h3.rs:152 and :157, type Value = ConfigSelection<T> at src/config/types/selection.rs:98 resolves to rule_set/geodata.rs:30, and type Udp = ... at src/dns/proxy_runtime.rs:82 resolves to wireguard/io.rs:79.
A file-local type alias is never registered as a local name, so a use of it falls through to the tree: type Connection (src/dns/exchange.rs:18, used at :27) resolves to xhttp/h3.rs:12, and type Reservation (src/xhttp/stream.rs:630, used at :626) resolves to xhttp/carrier.rs:26.
Gating the tree-wide lookup on a glob import covers all three cases.
Associated-type labels are still counted when the tree declares a type of the same name in the same file. A glob gate on the tree-wide lookup does not reach that case, because the name resolves locally before the lookup runs.
Neither type refers to struct Item. Item is the label of Iterator<Item = ..> and of type Item = u8;. A label such as Item, Target, Output or Error is not a type reference wherever the same-named type is declared.
The tree-wide case is widespread on EmbarkStudios/quilkin@58f4f0b: 54 of its 515 listed Rust types carry a dependency that comes only from such a label. Item (a private struct in src/net/io/nic/xdp/process.rs:307) is counted for 28 types through impl Iterator<Item = ..>. Target (a private enum in crates/test/src/bin/loadtest/main.rs:136) is counted for 10 types whose only use is impl Deref { type Target = ..; }. Configuration (pub trait Configuration in crates/xds/src/config.rs:236) is counted for 15 filters and the StaticFilter trait, through type Configuration = Config;. Six types drop from high to medium once these entries are removed: Pass, Capture, Debug, Drop, Match and HashedTokenRouter. Pass (src/filters/pass.rs:24) is a unit struct with no-op read/write methods, and it is reported at CBO 8, high.
polyscan version 0.6.1. Found via the polyscan-enhancement-audit skill.
Activity
DaisukeYoda commentedon Oct 31, 2026
The same fallback also fires on two other kinds of bare name, found by the triage pass on
cfal/shoeswith an instrumented build:type Send = UdpSender;andtype Recv = UdpReceiver;atsrc/wireguard/io.rs:133-134resolve tosrc/xhttp/h3.rs:152and:157,type Value = ConfigSelection<T>atsrc/config/types/selection.rs:98resolves torule_set/geodata.rs:30, andtype Udp = ...atsrc/dns/proxy_runtime.rs:82resolves towireguard/io.rs:79.type Connection(src/dns/exchange.rs:18, used at:27) resolves toxhttp/h3.rs:12, andtype Reservation(src/xhttp/stream.rs:630, used at:626) resolves toxhttp/carrier.rs:26.Gating the tree-wide lookup on a glob import covers all three cases.
DaisukeYoda commentedon Nov 7, 2026
Associated-type labels are still counted when the tree declares a type of the same name in the same file. A glob gate on the tree-wide lookup does not reach that case, because the name resolves locally before the lookup runs.
polyscan analyze --format json --select cbo .prints:{"name":"Numbers","coupling_count":1,"dependent_classes":["Item"]} {"name":"Counter","coupling_count":1,"dependent_classes":["Item"]}Neither type refers to
struct Item.Itemis the label ofIterator<Item = ..>and oftype Item = u8;. A label such asItem,Target,OutputorErroris not a type reference wherever the same-named type is declared.The tree-wide case is widespread on
EmbarkStudios/quilkin@58f4f0b: 54 of its 515 listed Rust types carry a dependency that comes only from such a label.Item(a private struct insrc/net/io/nic/xdp/process.rs:307) is counted for 28 types throughimpl Iterator<Item = ..>.Target(a private enum incrates/test/src/bin/loadtest/main.rs:136) is counted for 10 types whose only use isimpl Deref { type Target = ..; }.Configuration(pub trait Configurationincrates/xds/src/config.rs:236) is counted for 15 filters and theStaticFiltertrait, throughtype Configuration = Config;. Six types drop from high to medium once these entries are removed:Pass,Capture,Debug,Drop,MatchandHashedTokenRouter.Pass(src/filters/pass.rs:24) is a unit struct with no-opread/writemethods, and it is reported at CBO 8, high.polyscan version 0.6.1. Found via the polyscan-enhancement-audit skill.