pedant_core/resolution/rust/
warning.rs1use std::collections::BTreeMap;
5use std::fmt;
6use std::sync::Arc;
7
8use super::snapshot::RustResolutionUnit;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum RustResolutionWarning {
14 SharedSourceUnits {
18 path: Arc<str>,
20 units: Box<[Arc<str>]>,
22 },
23}
24
25impl RustResolutionWarning {
26 pub fn path(&self) -> &str {
28 match self {
29 Self::SharedSourceUnits { path, .. } => path,
30 }
31 }
32
33 pub fn unit_keys(&self) -> &[Arc<str>] {
35 match self {
36 Self::SharedSourceUnits { units, .. } => units,
37 }
38 }
39}
40
41impl fmt::Display for RustResolutionWarning {
42 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
43 match self {
44 Self::SharedSourceUnits { path, units } => {
45 write!(
46 formatter,
47 "{path} is instantiated by multiple resolution units ("
48 )?;
49 write_unit_keys(formatter, units)?;
50 formatter.write_str(
51 "), but rust-analyzer cannot distinguish their semantic contexts for one \
52 physical source; give each unit its own physical source, or, when the units \
53 share a package library, declare the module only there and reference it \
54 through the library crate",
55 )
56 }
57 }
58 }
59}
60
61pub(in crate::resolution::rust) fn unit_key(unit: &RustResolutionUnit) -> Arc<str> {
63 Arc::from(format!(
64 "{}#{}#{}",
65 unit.manifest_path(),
66 unit.kind().token(),
67 unit.name()
68 ))
69}
70
71pub(super) fn shared_sources(units: &[RustResolutionUnit]) -> Box<[RustResolutionWarning]> {
73 let mut owners: BTreeMap<Arc<str>, Vec<Arc<str>>> = BTreeMap::new();
74 for unit in units {
75 let key = unit_key(unit);
76 for path in unit.sources() {
77 owners
78 .entry(Arc::clone(path))
79 .or_default()
80 .push(Arc::clone(&key));
81 }
82 }
83 owners
84 .into_iter()
85 .filter_map(|(path, mut unit_keys)| {
86 unit_keys.sort();
87 unit_keys.dedup();
88 match unit_keys.len() > 1 {
89 true => Some(RustResolutionWarning::SharedSourceUnits {
90 path,
91 units: unit_keys.into_boxed_slice(),
92 }),
93 false => None,
94 }
95 })
96 .collect()
97}
98
99fn write_unit_keys(formatter: &mut fmt::Formatter<'_>, units: &[Arc<str>]) -> fmt::Result {
100 for (index, unit) in units.iter().enumerate() {
101 match index {
102 0 => formatter.write_str(unit)?,
103 _ => write!(formatter, ", {unit}")?,
104 }
105 }
106 Ok(())
107}