use crate::{
core::{Ident, SymbolPath, Value},
partitions::SymbolEntry,
};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SymbolUsage {
Definition,
Reference,
Binding,
}
#[derive(Debug)]
pub struct PositionEntry<V, I, P>
where
V: Value<I>,
I: Ident,
P: SymbolPath,
{
pub(crate) symbol_id: SymbolEntry<V, I, P>,
pub(crate) usage: SymbolUsage,
}
impl<V, I, P> Clone for PositionEntry<V, I, P>
where
V: Value<I>,
I: Ident,
P: SymbolPath,
{
fn clone(&self) -> Self {
Self {
symbol_id: self.symbol_id,
usage: self.usage.clone(),
}
}
}
#[derive(Debug)]
pub struct SymbolInfo<V, I, P>
where
V: Value<I>,
I: Ident,
P: SymbolPath,
{
pub(crate) symbol_id: SymbolEntry<V, I, P>,
pub usage: SymbolUsage,
}
impl<V, I, P> Clone for SymbolInfo<V, I, P>
where
V: Value<I>,
I: Ident,
P: SymbolPath,
{
fn clone(&self) -> Self {
Self {
symbol_id: self.symbol_id,
usage: self.usage.clone(),
}
}
}
#[cfg(test)]
impl<V, I, P> SymbolInfo<V, I, P>
where
V: Value<I>,
I: Ident,
P: SymbolPath,
{
pub(crate) fn new(
symbol_id: SymbolEntry<V, I, P>,
usage: SymbolUsage,
) -> Self {
Self { symbol_id, usage }
}
}
impl<V, I, P> SymbolInfo<V, I, P>
where
V: Value<I>,
I: Ident,
P: SymbolPath,
{
pub fn span(&self) -> laburnum::Span {
self.symbol_id.span
}
pub fn contains_position(
&self,
cache: &laburnum::SpanCache,
position: u32,
) -> bool {
self.symbol_id.span.contains(cache, position)
}
pub fn is_definition(&self) -> bool {
matches!(self.usage, SymbolUsage::Definition)
}
pub fn is_reference(&self) -> bool {
matches!(self.usage, SymbolUsage::Reference)
}
pub fn is_binding(&self) -> bool {
matches!(self.usage, SymbolUsage::Binding)
}
pub fn symbol_entry(&self) -> SymbolEntry<V, I, P> {
self.symbol_id
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_helpers::*;
#[test]
fn symbol_usage_variants_distinct() {
assert_ne!(SymbolUsage::Definition, SymbolUsage::Reference);
assert_ne!(SymbolUsage::Definition, SymbolUsage::Binding);
assert_ne!(SymbolUsage::Reference, SymbolUsage::Binding);
}
#[test]
fn symbol_info_is_definition() {
let mut cache = test_span_cache();
let info =
SymbolInfo::<DV, SI, TP>::new(dummy_symbol_entry(&mut cache), SymbolUsage::Definition);
assert!(info.is_definition());
assert!(!info.is_reference());
assert!(!info.is_binding());
}
#[test]
fn symbol_info_is_reference() {
let mut cache = test_span_cache();
let info =
SymbolInfo::<DV, SI, TP>::new(dummy_symbol_entry(&mut cache), SymbolUsage::Reference);
assert!(info.is_reference());
assert!(!info.is_definition());
assert!(!info.is_binding());
}
#[test]
fn symbol_info_is_binding() {
let mut cache = test_span_cache();
let info =
SymbolInfo::<DV, SI, TP>::new(dummy_symbol_entry(&mut cache), SymbolUsage::Binding);
assert!(info.is_binding());
assert!(!info.is_definition());
assert!(!info.is_reference());
}
#[test]
fn symbol_info_span_returns_entry_span() {
let mut cache = test_span_cache();
let entry = dummy_symbol_entry(&mut cache);
let expected_span = entry.span;
let info = SymbolInfo::<DV, SI, TP>::new(entry, SymbolUsage::Definition);
assert_eq!(info.span(), expected_span);
}
#[test]
fn symbol_info_symbol_entry() {
let mut cache = test_span_cache();
let entry = dummy_symbol_entry(&mut cache);
let info = SymbolInfo::<DV, SI, TP>::new(entry, SymbolUsage::Definition);
let returned = info.symbol_entry();
assert_eq!(returned.span, entry.span);
}
}