use bitflags::bitflags;
use oxc_index::define_nonmax_u32_index_type;
#[cfg(feature = "serialize")]
use serde::Serialize;
use oxc_allocator::{Allocator, CloneIn};
use crate::{node::NodeId, scope::ScopeId, symbol::SymbolId};
use oxc_ast_macros::ast;
define_nonmax_u32_index_type! {
#[ast]
#[builder(default)]
#[clone_in(default)]
#[content_eq(skip)]
#[estree(skip)]
pub struct ReferenceId;
}
impl<'alloc> CloneIn<'alloc> for ReferenceId {
type Cloned = Self;
fn clone_in(&self, _: &'alloc Allocator) -> Self {
unreachable!();
}
#[expect(clippy::inline_always)]
#[inline(always)]
fn clone_in_with_semantic_ids(&self, _: &'alloc Allocator) -> Self {
*self
}
}
bitflags! {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
pub struct ReferenceFlags: u8 {
const None = 0;
const Read = 1 << 0;
const Write = 1 << 1;
const Type = 1 << 2;
const ValueAsType = 1 << 3;
const Namespace = 1 << 4;
const Value = Self::Read.bits() | Self::Write.bits();
}
}
impl ReferenceFlags {
#[inline]
pub const fn read() -> Self {
Self::Read
}
#[inline]
pub const fn write() -> Self {
Self::Write
}
#[inline]
pub const fn read_write() -> Self {
Self::Value
}
#[inline]
pub const fn is_read(self) -> bool {
self.intersects(Self::Read)
}
#[inline]
pub const fn is_read_only(self) -> bool {
!self.contains(Self::Write)
}
#[inline]
pub const fn is_write(self) -> bool {
self.intersects(Self::Write)
}
#[inline]
pub const fn is_write_only(self) -> bool {
!self.contains(Self::Read)
}
#[inline]
pub fn is_read_write(self) -> bool {
self.contains(Self::Read | Self::Write)
}
#[inline]
pub fn is_value_as_type(self) -> bool {
self.contains(Self::ValueAsType)
}
#[inline]
pub const fn is_type(self) -> bool {
self.contains(Self::Type)
}
#[inline]
pub const fn is_type_only(self) -> bool {
matches!(self, Self::Type)
}
#[inline]
pub const fn is_value(self) -> bool {
self.intersects(Self::Value)
}
#[inline]
pub const fn is_namespace(self) -> bool {
self.contains(Self::Namespace)
}
}
impl<'alloc> CloneIn<'alloc> for ReferenceFlags {
type Cloned = Self;
fn clone_in(&self, _: &'alloc oxc_allocator::Allocator) -> Self::Cloned {
*self
}
}
#[cfg_attr(feature = "serialize", derive(Serialize), serde(rename_all = "camelCase"))]
#[derive(Debug, Clone)]
pub struct Reference {
node_id: NodeId,
symbol_id: Option<SymbolId>,
scope_id: ScopeId,
flags: ReferenceFlags,
}
impl Reference {
#[inline]
pub fn new(node_id: NodeId, scope_id: ScopeId, flags: ReferenceFlags) -> Self {
Self { node_id, symbol_id: None, scope_id, flags }
}
#[inline]
pub fn new_with_symbol_id(
node_id: NodeId,
symbol_id: SymbolId,
scope_id: ScopeId,
flags: ReferenceFlags,
) -> Self {
Self { node_id, symbol_id: Some(symbol_id), scope_id, flags }
}
#[inline]
pub fn node_id(&self) -> NodeId {
self.node_id
}
#[inline]
pub fn symbol_id(&self) -> Option<SymbolId> {
self.symbol_id
}
#[inline]
pub fn set_symbol_id(&mut self, symbol_id: SymbolId) {
self.symbol_id = Some(symbol_id);
}
#[inline]
pub fn scope_id(&self) -> ScopeId {
self.scope_id
}
#[inline]
pub fn flags(&self) -> ReferenceFlags {
self.flags
}
#[inline]
pub fn flags_mut(&mut self) -> &mut ReferenceFlags {
&mut self.flags
}
#[inline]
pub fn is_read(&self) -> bool {
self.flags.is_read()
}
#[inline]
pub fn is_write(&self) -> bool {
self.flags.is_write()
}
pub fn is_value(&self) -> bool {
self.flags.is_value()
}
#[inline]
pub fn is_type(&self) -> bool {
self.flags.is_type()
}
}