use crate::{
project::{PkgHandle, Project},
syntax::cst::{
tree::{NodeHandle, NodeRef},
view::View,
},
};
use super::{
name::SymName,
node::{node_is_def, node_is_implicit_def, node_is_ref},
};
pub fn find_references_for(
proj: &Project,
this_pkg: PkgHandle,
node: NodeRef<'_>,
project_wide: bool,
include_declaration: bool,
) -> Option<Vec<(PkgHandle, NodeHandle)>> {
if node_is_ref(node) {
if let Some((pkg, node)) = find_definition(proj, this_pkg, node.handle()) {
Some(find_references(
proj,
pkg,
node,
project_wide || this_pkg != pkg,
include_declaration,
))
} else {
None
}
} else if node_is_def(node) {
Some(find_references(
proj,
this_pkg,
node.handle(),
project_wide,
include_declaration,
))
} else if let Some(name) = node_is_implicit_def(node) {
let (pkg, node) = find_definition(proj, this_pkg, name.syntax().handle())
.unwrap_or((this_pkg, node.handle()));
Some(find_references(proj, pkg, node, false, include_declaration))
} else {
return None;
}
}
pub fn definition_for(
proj: &Project,
pkg: PkgHandle,
node: NodeRef<'_>,
) -> Option<(PkgHandle, NodeHandle)> {
if node_is_ref(node) {
find_definition(proj, pkg, node.handle())
} else if node_is_def(node) {
Some((pkg, node.handle()))
} else {
None
}
}
pub fn find_definition(
proj: &Project,
pkg: PkgHandle,
node: NodeHandle,
) -> Option<(PkgHandle, NodeHandle)> {
let bindings = proj.bindings.get(proj, pkg);
bindings.get(node)
}
pub fn find_references(
proj: &Project,
pkg: PkgHandle,
node: NodeHandle,
project_wide: bool,
include_declaration: bool,
) -> Vec<(PkgHandle, NodeHandle)> {
let bindings = proj.bindings.get(proj, pkg);
let mut out = Vec::new();
if include_declaration {
out.push((pkg, node));
}
for (n, def) in bindings.iter() {
if def == (pkg, node) {
out.push((pkg, n));
}
}
if !project_wide {
return out;
}
let exports = proj.exports.get(proj, pkg);
if !exports.defs.iter().any(|(_, v)| *v == (pkg, node)) {
return out;
}
let this_pkg = pkg;
let Some(this_pkg_name) = proj.get_pkg(this_pkg).name.clone() else {
return out;
};
for pkg in proj.iter_packages() {
if pkg == this_pkg {
continue;
}
if exports
.defs
.get(&SymName::Pkg(this_pkg_name.clone()))
.map(|(pkg, _)| *pkg)
!= Some(this_pkg)
{
continue;
}
let bindings = proj.bindings.get(proj, pkg);
for (n, def) in bindings.iter() {
if def == (this_pkg, node) {
out.push((pkg, n));
}
}
}
out
}