use std::ops::Range;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::model::names::{Arity, FunctionName, Mfa, ModuleName, RecordName, TypeName};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum RefContext {
Body,
TypeAttribute,
OtherAttribute,
RecordAttribute,
AttributeString,
}
impl RefContext {
#[must_use]
pub fn is_attribute(self) -> bool {
!matches!(self, Self::Body)
}
#[must_use]
pub fn holds_calls(self) -> bool {
matches!(
self,
Self::Body | Self::OtherAttribute | Self::RecordAttribute
)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LineClass {
pub context: RefContext,
pub type_spans: Vec<Range<usize>>,
}
impl LineClass {
#[must_use]
pub fn new(context: RefContext) -> Self {
Self {
context,
type_spans: Vec::new(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum SymbolKind {
Behaviour {
module: ModuleName,
},
Callback {
module: ModuleName,
function: FunctionName,
arity: Arity,
},
Function {
mfa: Mfa,
},
FunctionAnyArity {
module: ModuleName,
function: FunctionName,
},
Macro {
name: String,
},
Record {
name: RecordName,
},
Type {
module: ModuleName,
name: TypeName,
arity: Arity,
},
}
#[derive(Debug, Clone, Copy)]
pub enum ExportedSymbol<'a> {
Function(&'a Mfa),
FunctionAnyArity {
module: &'a ModuleName,
function: &'a FunctionName,
},
Type {
module: &'a ModuleName,
name: &'a TypeName,
arity: Arity,
},
}
impl SymbolKind {
#[must_use]
pub fn as_exported(&self) -> Option<ExportedSymbol<'_>> {
match self {
Self::Function { mfa } => Some(ExportedSymbol::Function(mfa)),
Self::FunctionAnyArity { module, function } => {
Some(ExportedSymbol::FunctionAnyArity { module, function })
}
Self::Type {
module,
name,
arity,
} => Some(ExportedSymbol::Type {
module,
name,
arity: *arity,
}),
Self::Behaviour { .. }
| Self::Callback { .. }
| Self::Macro { .. }
| Self::Record { .. } => None,
}
}
}
#[derive(
Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename_all = "snake_case")]
pub enum RefOrigin {
#[default]
Added,
Context,
}
impl RefOrigin {
#[allow(clippy::trivially_copy_pass_by_ref)]
#[must_use]
pub fn is_added(&self) -> bool {
matches!(self, Self::Added)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct SymbolRef {
#[serde(flatten)]
pub kind: SymbolKind,
#[serde(default, skip_serializing_if = "RefOrigin::is_added")]
pub origin: RefOrigin,
}
impl SymbolRef {
pub fn function(mfa: Mfa) -> Self {
Self {
kind: SymbolKind::Function { mfa },
origin: RefOrigin::Added,
}
}
pub fn function_any_arity(module: ModuleName, function: FunctionName) -> Self {
Self {
kind: SymbolKind::FunctionAnyArity { module, function },
origin: RefOrigin::Added,
}
}
pub fn record(name: RecordName) -> Self {
Self {
kind: SymbolKind::Record { name },
origin: RefOrigin::Added,
}
}
pub fn macro_use(name: impl Into<String>) -> Self {
Self {
kind: SymbolKind::Macro { name: name.into() },
origin: RefOrigin::Added,
}
}
pub fn type_ref(module: ModuleName, name: TypeName, arity: Arity) -> Self {
Self {
kind: SymbolKind::Type {
module,
name,
arity,
},
origin: RefOrigin::Added,
}
}
#[must_use]
pub fn with_origin(mut self, origin: RefOrigin) -> Self {
self.origin = origin;
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Reference {
pub symbol: SymbolRef,
pub from_path: PathBuf,
pub line: usize,
}