Skip to content

Commit aa71d9c

Browse files
committed
Expose exported_symbols in Package
1 parent f749b8e commit aa71d9c

File tree

2 files changed

+98
-10
lines changed

2 files changed

+98
-10
lines changed

crates/ark/src/lsp/diagnostics.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ fn insert_package_exports(
957957
.library_symbols
958958
.entry(attach_pos)
959959
.or_default()
960-
.extend(package.namespace.exports.iter().cloned());
960+
.extend(package.exported_symbols.iter().cloned());
961961

962962
Ok(package)
963963
}
@@ -1657,7 +1657,7 @@ foo
16571657
depends: vec![],
16581658
fields: Dcf::new(),
16591659
};
1660-
let package = Package::new(PathBuf::from("/mock/path"), description, namespace);
1660+
let package = Package::from_parts(PathBuf::from("/mock/path"), description, namespace);
16611661

16621662
// Create a library with `mockpkg` installed
16631663
let library = Library::new(vec![]).insert("mockpkg", package);
@@ -1753,7 +1753,8 @@ foo
17531753
depends: vec![],
17541754
fields: Dcf::new(),
17551755
};
1756-
let package1 = Package::new(PathBuf::from("/mock/path1"), description1, namespace1);
1756+
let package1 =
1757+
Package::from_parts(PathBuf::from("/mock/path1"), description1, namespace1);
17571758

17581759
// pkg2 exports `bar` and `baz`
17591760
let namespace2 = Namespace {
@@ -1767,7 +1768,8 @@ foo
17671768
depends: vec![],
17681769
fields: Dcf::new(),
17691770
};
1770-
let package2 = Package::new(PathBuf::from("/mock/path2"), description2, namespace2);
1771+
let package2 =
1772+
Package::from_parts(PathBuf::from("/mock/path2"), description2, namespace2);
17711773

17721774
let library = Library::new(vec![])
17731775
.insert("pkg1", package1)
@@ -1823,7 +1825,7 @@ foo
18231825
depends: vec![],
18241826
fields: Dcf::new(),
18251827
};
1826-
let package = Package::new(PathBuf::from("/mock/path"), description, namespace);
1828+
let package = Package::from_parts(PathBuf::from("/mock/path"), description, namespace);
18271829

18281830
let library = Library::new(vec![]).insert("pkg", package);
18291831

crates/ark/src/lsp/inputs/package.rs

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,50 @@ pub struct Package {
2222
pub description: Description,
2323
pub namespace: Namespace,
2424
pub documentation: Documentation,
25+
26+
// List of symbols exported via NAMESPACE `export()` directives and via
27+
// `DocType{data}`. Note the latter should only apply to packages with
28+
// `LazyData: true` but currently applies to all packages, as a stopgap
29+
// to prevent spurious diagnostics (we accept false negatives to avoid
30+
// annoying false positives).
31+
pub exported_symbols: Vec<String>,
2532
}
2633

2734
impl Package {
28-
pub fn new(path: PathBuf, description: Description, namespace: Namespace) -> Self {
35+
pub fn new(
36+
path: PathBuf,
37+
description: Description,
38+
namespace: Namespace,
39+
documentation: Documentation,
40+
) -> Self {
41+
// Compute exported symbols. Start from explicit NAMESPACE exports.
42+
let mut exported_symbols = namespace.exports.clone();
43+
44+
// Add exported datasets. Ideally we'd only do that for packages
45+
// specifying `LazyData: true`.
46+
let exported_datasets = documentation.rd_files.iter().filter_map(|rd| {
47+
if rd.doc_type == Some(crate::lsp::inputs::documentation_rd_file::RdDocType::Data) {
48+
rd.name.clone()
49+
} else {
50+
None
51+
}
52+
});
53+
exported_symbols.extend(exported_datasets);
54+
2955
Self {
3056
path,
3157
description,
3258
namespace,
33-
documentation: Default::default(),
59+
documentation,
60+
exported_symbols,
3461
}
3562
}
3663

64+
#[cfg(test)]
65+
pub fn from_parts(path: PathBuf, description: Description, namespace: Namespace) -> Self {
66+
Self::new(path, description, namespace, Default::default())
67+
}
68+
3769
/// Load a package from a given path.
3870
pub fn load_from_folder(package_path: &std::path::Path) -> anyhow::Result<Option<Self>> {
3971
let description_path = package_path.join("DESCRIPTION");
@@ -69,12 +101,12 @@ impl Package {
69101
},
70102
};
71103

72-
Ok(Some(Package {
73-
path: package_path.to_path_buf(),
104+
Ok(Some(Self::new(
105+
package_path.to_path_buf(),
74106
description,
75107
namespace,
76108
documentation,
77-
}))
109+
)))
78110
}
79111

80112
/// Load a package from the given library path and name.
@@ -98,3 +130,57 @@ impl Package {
98130
}
99131
}
100132
}
133+
134+
#[cfg(test)]
135+
mod tests {
136+
use super::*;
137+
use crate::lsp::inputs::documentation_rd_file::RdDocType;
138+
use crate::lsp::inputs::documentation_rd_file::RdFile;
139+
use crate::lsp::inputs::package_description::Description;
140+
use crate::lsp::inputs::package_namespace::Namespace;
141+
142+
#[test]
143+
fn test_exported_symbols_combining_namespace_and_rd_files() {
144+
let namespace = Namespace {
145+
exports: vec!["foo".to_string(), "bar".to_string()],
146+
..Default::default()
147+
};
148+
149+
let rd_files = vec![
150+
RdFile {
151+
name: Some("data1".to_string()),
152+
doc_type: Some(RdDocType::Data),
153+
},
154+
RdFile {
155+
name: Some("pkgdoc".to_string()),
156+
doc_type: Some(RdDocType::Package),
157+
},
158+
RdFile {
159+
name: Some("other".to_string()),
160+
doc_type: None,
161+
},
162+
];
163+
let documentation = Documentation { rd_files };
164+
165+
let description = Description {
166+
name: "mypkg".to_string(),
167+
version: "1.0.0".to_string(),
168+
depends: vec![],
169+
fields: Default::default(),
170+
};
171+
172+
let package = Package::new(
173+
PathBuf::from("/mock/path"),
174+
description,
175+
namespace,
176+
documentation,
177+
);
178+
179+
assert!(package.exported_symbols.contains(&"foo".to_string()));
180+
assert!(package.exported_symbols.contains(&"bar".to_string()));
181+
assert!(package.exported_symbols.contains(&"data1".to_string()));
182+
183+
assert!(!package.exported_symbols.contains(&"pkgdoc".to_string()));
184+
assert!(!package.exported_symbols.contains(&"other".to_string()));
185+
}
186+
}

0 commit comments

Comments
 (0)