1use crate::accessor::Accessor;
7use crate::async_symbol::AsyncSymbol;
8use crate::autodiff::AutoDiff;
9use crate::closure::Closure;
10use crate::constructor::{Constructor, Destructor};
11use crate::descriptor::Descriptor;
12use crate::enum_case::EnumCase;
13use crate::function::Function;
14use crate::helpers::{HasModule, NodeExt};
15use crate::macro_symbol::MacroSymbol;
16use crate::metadata::Metadata;
17use crate::outlined::Outlined;
18use crate::raw::{Context, Node, NodeKind};
19use crate::specialization::Specialization;
20use crate::thunk::Thunk;
21use crate::types::TypeRef;
22use crate::witness_table::WitnessTable;
23
24#[derive(Debug)]
29pub enum Symbol<'ctx> {
30 Function(Function<'ctx>),
32 Constructor(Constructor<'ctx>),
34 Destructor(Destructor<'ctx>),
36 EnumCase(EnumCase<'ctx>),
38 Accessor(Accessor<'ctx>),
40 Variable(Variable<'ctx>),
42 Closure(Closure<'ctx>),
44 Thunk(Thunk<'ctx>),
46 Specialization(SpecializedSymbol<'ctx>),
48 WitnessTable(WitnessTable<'ctx>),
50 Descriptor(Descriptor<'ctx>),
52 Metadata(Metadata<'ctx>),
54 Type(TypeRef<'ctx>),
56 Attributed(AttributedSymbol<'ctx>),
58 DefaultArgument(DefaultArgument<'ctx>),
60 Outlined(OutlinedSymbol<'ctx>),
62 Async(AsyncSymbol<'ctx>),
64 Macro(MacroSymbol<'ctx>),
66 AutoDiff(AutoDiff<'ctx>),
68 Identifier(Node<'ctx>),
70 Suffixed(SuffixedSymbol<'ctx>),
72 Other(Node<'ctx>),
74}
75
76pub struct AttributedSymbol<'ctx> {
78 pub attribute: SymbolAttribute,
80 pub inner: Box<Symbol<'ctx>>,
82 raw: Node<'ctx>,
84}
85
86impl<'ctx> AttributedSymbol<'ctx> {
87 pub fn raw(&self) -> Node<'ctx> {
89 self.raw
90 }
91}
92
93impl std::fmt::Debug for AttributedSymbol<'_> {
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95 f.debug_struct("AttributedSymbol")
96 .field("attribute", &self.attribute)
97 .field("inner", &self.inner)
98 .finish()
99 }
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
104pub enum SymbolAttribute {
105 ObjC,
107 NonObjC,
109 Dynamic,
111 Distributed,
113}
114
115impl SymbolAttribute {
116 pub fn name(&self) -> &'static str {
118 match self {
119 SymbolAttribute::ObjC => "@objc",
120 SymbolAttribute::NonObjC => "@nonobjc",
121 SymbolAttribute::Dynamic => "dynamic",
122 SymbolAttribute::Distributed => "distributed",
123 }
124 }
125}
126
127pub struct DefaultArgument<'ctx> {
129 raw: Node<'ctx>,
130}
131
132impl<'ctx> DefaultArgument<'ctx> {
133 pub fn new(raw: Node<'ctx>) -> Self {
135 Self { raw }
136 }
137
138 pub fn raw(&self) -> Node<'ctx> {
140 self.raw
141 }
142
143 pub fn index(&self) -> Option<u64> {
145 for child in self.raw.children() {
146 if child.kind() == NodeKind::Number {
147 return child.index();
148 }
149 }
150 None
151 }
152
153 pub fn function(&self) -> Option<Function<'ctx>> {
155 for child in self.raw.children() {
156 if child.kind() == NodeKind::Function {
157 return Some(Function::new(child));
158 }
159 }
160 None
161 }
162
163 pub fn module(&self) -> Option<&'ctx str> {
165 self.function().and_then(|f| f.module())
166 }
167}
168
169impl std::fmt::Debug for DefaultArgument<'_> {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 f.debug_struct("DefaultArgument")
172 .field("index", &self.index())
173 .field("function", &self.function())
174 .field("module", &self.module())
175 .finish()
176 }
177}
178
179#[derive(Debug)]
181pub struct SpecializedSymbol<'ctx> {
182 pub specialization: Specialization<'ctx>,
184 pub inner: Box<Symbol<'ctx>>,
186}
187
188#[derive(Debug)]
190pub struct OutlinedSymbol<'ctx> {
191 pub outlined: Outlined<'ctx>,
193 pub context: Box<Symbol<'ctx>>,
195}
196
197#[derive(Debug)]
199pub struct SuffixedSymbol<'ctx> {
200 pub suffix: &'ctx str,
202 pub inner: Box<Symbol<'ctx>>,
204}
205
206impl<'ctx> Symbol<'ctx> {
207 pub fn parse(ctx: &'ctx Context, mangled: &str) -> Option<Self> {
211 let root = Node::parse(ctx, mangled)?;
212 Self::from_node(root)
213 }
214
215 pub fn from_node(root: Node<'ctx>) -> Option<Self> {
219 if root.kind() != NodeKind::Global {
220 return None;
221 }
222
223 let first_child = root.child(0)?;
224
225 if Self::is_specialization_kind(first_child.kind()) {
229 return Some(Self::build_specialization_chain(root, 0));
231 }
232
233 if Self::is_outlined_kind(first_child.kind()) {
237 let mut context_idx = 1;
239 let mut attr_nodes = Vec::new();
240 while let Some(node) = root.child(context_idx) {
241 if Self::get_attribute_kind(node.kind()).is_some() {
242 attr_nodes.push(node);
243 context_idx += 1;
244 } else if node.kind() == NodeKind::Suffix {
245 context_idx += 1;
247 } else {
248 break;
249 }
250 }
251
252 if let Some(context_node) = root.child(context_idx) {
253 let mut context = Self::classify(context_node);
255 for attr_node in attr_nodes.into_iter().rev() {
257 if let Some(attr) = Self::get_attribute_kind(attr_node.kind()) {
258 context = Symbol::Attributed(AttributedSymbol {
259 attribute: attr,
260 inner: Box::new(context),
261 raw: attr_node,
262 });
263 }
264 }
265 return Some(Symbol::Outlined(OutlinedSymbol {
266 outlined: Outlined::new(first_child),
267 context: Box::new(context),
268 }));
269 }
270 if let Some(type_ref) = first_child.extract_type_ref() {
273 return Some(Symbol::Outlined(OutlinedSymbol {
274 outlined: Outlined::new(first_child),
275 context: Box::new(Symbol::Type(type_ref)),
276 }));
277 }
278 return Some(Symbol::Outlined(OutlinedSymbol {
280 outlined: Outlined::new(first_child),
281 context: Box::new(Symbol::Other(first_child)),
282 }));
283 }
284
285 if let Some(attribute) = Self::get_attribute_kind(first_child.kind())
288 && let Some(inner_node) = root.child(1)
289 {
290 let inner = Self::classify(inner_node);
291 return Some(Symbol::Attributed(AttributedSymbol {
292 attribute,
293 inner: Box::new(inner),
294 raw: first_child,
295 }));
296 }
297
298 if Self::is_async_marker_kind(first_child.kind())
301 || Self::is_metadata_marker_kind(first_child.kind())
302 || Self::is_thunk_marker_kind(first_child.kind())
303 {
304 return Some(Self::build_marker_chain(root, 0));
305 }
306
307 let suffix = root.child_of_kind(NodeKind::Suffix).and_then(|c| c.text());
309
310 let inner = Self::classify(first_child);
311
312 if let Some(suffix) = suffix {
313 Some(Symbol::Suffixed(SuffixedSymbol {
314 suffix,
315 inner: Box::new(inner),
316 }))
317 } else {
318 Some(inner)
319 }
320 }
321
322 fn is_specialization_kind(kind: NodeKind) -> bool {
323 matches!(
324 kind,
325 NodeKind::GenericSpecialization
326 | NodeKind::GenericSpecializationNotReAbstracted
327 | NodeKind::GenericSpecializationInResilienceDomain
328 | NodeKind::GenericSpecializationPrespecialized
329 | NodeKind::GenericPartialSpecialization
330 | NodeKind::GenericPartialSpecializationNotReAbstracted
331 | NodeKind::FunctionSignatureSpecialization
332 )
333 }
334
335 fn build_specialization_chain(root: Node<'ctx>, index: usize) -> Symbol<'ctx> {
341 let Some(current) = root.child(index) else {
342 return Symbol::Other(root);
344 };
345
346 if Self::is_specialization_kind(current.kind()) {
347 let inner = if let Some(next) = root.child(index + 1) {
349 if Self::is_specialization_kind(next.kind()) {
350 Self::build_specialization_chain(root, index + 1)
352 } else {
353 Self::classify(next)
355 }
356 } else {
357 Symbol::Other(current)
359 };
360
361 Symbol::Specialization(SpecializedSymbol {
362 specialization: Specialization::new(current),
363 inner: Box::new(inner),
364 })
365 } else {
366 Self::classify(current)
368 }
369 }
370
371 fn build_marker_chain(root: Node<'ctx>, index: usize) -> Symbol<'ctx> {
376 let Some(current) = root.child(index) else {
377 return Symbol::Other(root);
378 };
379
380 let inner = if let Some(next) = root.child(index + 1) {
382 if Self::is_async_marker_kind(next.kind())
383 || Self::is_metadata_marker_kind(next.kind())
384 || Self::is_thunk_marker_kind(next.kind())
385 {
386 Self::build_marker_chain(root, index + 1)
388 } else {
389 Self::classify(next)
391 }
392 } else {
393 return Symbol::Other(current);
395 };
396
397 if Self::is_async_marker_kind(current.kind()) {
399 Symbol::Async(AsyncSymbol::with_inner(current, inner))
400 } else if Self::is_metadata_marker_kind(current.kind()) {
401 Symbol::Metadata(Metadata::with_inner(current, inner))
402 } else if Self::is_thunk_marker_kind(current.kind()) {
403 Symbol::Thunk(Thunk::new_marker(current, inner))
404 } else {
405 inner
407 }
408 }
409
410 fn is_outlined_kind(kind: NodeKind) -> bool {
411 matches!(
412 kind,
413 NodeKind::OutlinedBridgedMethod
414 | NodeKind::OutlinedVariable
415 | NodeKind::OutlinedCopy
416 | NodeKind::OutlinedConsume
417 | NodeKind::OutlinedRetain
418 | NodeKind::OutlinedRelease
419 | NodeKind::OutlinedInitializeWithTake
420 | NodeKind::OutlinedInitializeWithCopy
421 | NodeKind::OutlinedAssignWithTake
422 | NodeKind::OutlinedAssignWithCopy
423 | NodeKind::OutlinedDestroy
424 | NodeKind::OutlinedInitializeWithCopyNoValueWitness
425 | NodeKind::OutlinedInitializeWithTakeNoValueWitness
426 | NodeKind::OutlinedAssignWithCopyNoValueWitness
427 | NodeKind::OutlinedAssignWithTakeNoValueWitness
428 | NodeKind::OutlinedDestroyNoValueWitness
429 | NodeKind::OutlinedReadOnlyObject
430 )
431 }
432
433 fn get_attribute_kind(kind: NodeKind) -> Option<SymbolAttribute> {
434 match kind {
435 NodeKind::ObjCAttribute => Some(SymbolAttribute::ObjC),
436 NodeKind::NonObjCAttribute => Some(SymbolAttribute::NonObjC),
437 NodeKind::DynamicAttribute => Some(SymbolAttribute::Dynamic),
438 NodeKind::DistributedAccessor => Some(SymbolAttribute::Distributed),
439 _ => None,
440 }
441 }
442
443 fn is_async_marker_kind(kind: NodeKind) -> bool {
444 matches!(
445 kind,
446 NodeKind::CoroFunctionPointer
447 | NodeKind::AsyncFunctionPointer
448 | NodeKind::AsyncAwaitResumePartialFunction
449 | NodeKind::AsyncSuspendResumePartialFunction
450 )
451 }
452
453 fn is_metadata_marker_kind(kind: NodeKind) -> bool {
454 matches!(kind, NodeKind::DefaultOverride | NodeKind::HasSymbolQuery)
455 }
456
457 fn is_thunk_marker_kind(kind: NodeKind) -> bool {
458 matches!(
459 kind,
460 NodeKind::InlinedGenericFunction
461 | NodeKind::MergedFunction
462 | NodeKind::DistributedThunk
463 )
464 }
465
466 fn classify(node: Node<'ctx>) -> Self {
467 Self::classify_with_static(node, false)
468 }
469
470 pub fn classify_node(node: Node<'ctx>) -> Self {
474 Self::classify_with_static(node, false)
475 }
476
477 fn classify_with_static(node: Node<'ctx>, is_static: bool) -> Self {
478 match node.kind() {
479 NodeKind::Static => {
481 if let Some(inner) = node.child(0) {
482 return Self::classify_with_static(inner, true);
483 }
484 Symbol::Other(node)
485 }
486
487 NodeKind::Function => {
489 if is_static {
490 Symbol::Function(Function::new_static(node))
491 } else {
492 Symbol::Function(Function::new(node))
493 }
494 }
495
496 NodeKind::Constructor | NodeKind::Allocator => {
498 Symbol::Constructor(Constructor::new(node))
499 }
500
501 NodeKind::Destructor | NodeKind::Deallocator | NodeKind::IsolatedDeallocator => {
503 Symbol::Destructor(Destructor::new(node))
504 }
505
506 NodeKind::EnumCase => Symbol::EnumCase(EnumCase::new(node)),
508
509 NodeKind::Getter
511 | NodeKind::Setter
512 | NodeKind::ModifyAccessor
513 | NodeKind::Modify2Accessor
514 | NodeKind::ReadAccessor
515 | NodeKind::Read2Accessor
516 | NodeKind::WillSet
517 | NodeKind::DidSet
518 | NodeKind::GlobalGetter
519 | NodeKind::MaterializeForSet
520 | NodeKind::InitAccessor
521 | NodeKind::UnsafeAddressor
522 | NodeKind::UnsafeMutableAddressor
523 | NodeKind::OwningAddressor
524 | NodeKind::OwningMutableAddressor
525 | NodeKind::NativeOwningAddressor
526 | NodeKind::NativeOwningMutableAddressor
527 | NodeKind::NativePinningAddressor
528 | NodeKind::NativePinningMutableAddressor => {
529 if is_static {
530 Symbol::Accessor(Accessor::new_static(node))
531 } else {
532 Symbol::Accessor(Accessor::new(node))
533 }
534 }
535
536 NodeKind::Variable => Symbol::Variable(Variable::new(node)),
538
539 NodeKind::ExplicitClosure | NodeKind::ImplicitClosure => {
541 Symbol::Closure(Closure::new(node))
542 }
543
544 NodeKind::DispatchThunk
546 | NodeKind::VTableThunk
547 | NodeKind::DistributedThunk
548 | NodeKind::ReabstractionThunk
549 | NodeKind::ReabstractionThunkHelper
550 | NodeKind::ReabstractionThunkHelperWithSelf
551 | NodeKind::ReabstractionThunkHelperWithGlobalActor
552 | NodeKind::AutoDiffSelfReorderingReabstractionThunk
553 | NodeKind::PartialApplyForwarder
554 | NodeKind::PartialApplyObjCForwarder
555 | NodeKind::CurryThunk
556 | NodeKind::ProtocolWitness
557 | NodeKind::ProtocolSelfConformanceWitness
558 | NodeKind::KeyPathGetterThunkHelper
559 | NodeKind::KeyPathSetterThunkHelper
560 | NodeKind::KeyPathUnappliedMethodThunkHelper
561 | NodeKind::KeyPathAppliedMethodThunkHelper
562 | NodeKind::KeyPathEqualsThunkHelper
563 | NodeKind::KeyPathHashThunkHelper
564 | NodeKind::AutoDiffSubsetParametersThunk
565 | NodeKind::AutoDiffDerivativeVTableThunk
566 | NodeKind::BackDeploymentThunk
567 | NodeKind::BackDeploymentFallback
568 | NodeKind::MergedFunction
569 | NodeKind::InlinedGenericFunction => Symbol::Thunk(Thunk::new(node)),
570
571 NodeKind::ProtocolWitnessTable
573 | NodeKind::ProtocolWitnessTableAccessor
574 | NodeKind::ProtocolWitnessTablePattern
575 | NodeKind::GenericProtocolWitnessTable
576 | NodeKind::GenericProtocolWitnessTableInstantiationFunction
577 | NodeKind::ResilientProtocolWitnessTable
578 | NodeKind::LazyProtocolWitnessTableAccessor
579 | NodeKind::LazyProtocolWitnessTableCacheVariable
580 | NodeKind::ProtocolSelfConformanceWitnessTable
581 | NodeKind::ValueWitnessTable
582 | NodeKind::ValueWitness
583 | NodeKind::AssociatedTypeWitnessTableAccessor
584 | NodeKind::BaseWitnessTableAccessor
585 | NodeKind::ConcreteProtocolConformance => {
586 Symbol::WitnessTable(WitnessTable::new(node))
587 }
588
589 NodeKind::ProtocolConformanceDescriptor
591 | NodeKind::ProtocolConformanceDescriptorRecord
592 | NodeKind::OpaqueTypeDescriptor
593 | NodeKind::OpaqueTypeDescriptorRecord
594 | NodeKind::OpaqueTypeDescriptorAccessor
595 | NodeKind::OpaqueTypeDescriptorAccessorImpl
596 | NodeKind::OpaqueTypeDescriptorAccessorKey
597 | NodeKind::OpaqueTypeDescriptorAccessorVar
598 | NodeKind::NominalTypeDescriptor
599 | NodeKind::NominalTypeDescriptorRecord
600 | NodeKind::PropertyDescriptor
601 | NodeKind::ProtocolDescriptor
602 | NodeKind::ProtocolDescriptorRecord
603 | NodeKind::ProtocolRequirementsBaseDescriptor
604 | NodeKind::MethodDescriptor
605 | NodeKind::AssociatedTypeDescriptor
606 | NodeKind::AssociatedConformanceDescriptor
607 | NodeKind::DefaultAssociatedConformanceAccessor
608 | NodeKind::BaseConformanceDescriptor
609 | NodeKind::ExtensionDescriptor
610 | NodeKind::AnonymousDescriptor
611 | NodeKind::ModuleDescriptor
612 | NodeKind::ReflectionMetadataAssocTypeDescriptor
613 | NodeKind::AccessibleFunctionRecord => Symbol::Descriptor(Descriptor::new(node)),
614
615 NodeKind::TypeMetadata
617 | NodeKind::FullTypeMetadata
618 | NodeKind::TypeMetadataAccessFunction
619 | NodeKind::TypeMetadataCompletionFunction
620 | NodeKind::TypeMetadataInstantiationFunction
621 | NodeKind::TypeMetadataInstantiationCache
622 | NodeKind::TypeMetadataLazyCache
623 | NodeKind::TypeMetadataSingletonInitializationCache
624 | NodeKind::TypeMetadataDemanglingCache
625 | NodeKind::GenericTypeMetadataPattern
626 | NodeKind::MetadataInstantiationCache
627 | NodeKind::NoncanonicalSpecializedGenericTypeMetadata
628 | NodeKind::NoncanonicalSpecializedGenericTypeMetadataCache
629 | NodeKind::CanonicalSpecializedGenericTypeMetadataAccessFunction
630 | NodeKind::AssociatedTypeMetadataAccessor
631 | NodeKind::DefaultAssociatedTypeMetadataAccessor
632 | NodeKind::ClassMetadataBaseOffset
633 | NodeKind::ObjCMetadataUpdateFunction
634 | NodeKind::FieldOffset
635 | NodeKind::Metaclass
636 | NodeKind::IVarInitializer
637 | NodeKind::IVarDestroyer
638 | NodeKind::HasSymbolQuery
639 | NodeKind::DefaultOverride
640 | NodeKind::PropertyWrapperBackingInitializer
641 | NodeKind::MethodLookupFunction => Symbol::Metadata(Metadata::new(node)),
642
643 NodeKind::DefaultArgumentInitializer => {
645 Symbol::DefaultArgument(DefaultArgument::new(node))
646 }
647
648 NodeKind::TypeMangling => {
650 if let Some(type_node) = node.child(0) {
651 Symbol::Type(TypeRef::new(type_node))
652 } else {
653 Symbol::Other(node)
654 }
655 }
656
657 NodeKind::Class
659 | NodeKind::Structure
660 | NodeKind::Enum
661 | NodeKind::Protocol
662 | NodeKind::TypeAlias
663 | NodeKind::OtherNominalType
664 | NodeKind::BuiltinTypeName
665 | NodeKind::BoundGenericStructure
666 | NodeKind::BoundGenericClass
667 | NodeKind::BoundGenericEnum
668 | NodeKind::Tuple
669 | NodeKind::BuiltinFixedArray => Symbol::Type(TypeRef::new(node)),
670
671 NodeKind::Subscript => {
673 if is_static {
674 Symbol::Accessor(Accessor::new_static(node))
675 } else {
676 Symbol::Accessor(Accessor::new(node))
677 }
678 }
679
680 NodeKind::AsyncAwaitResumePartialFunction
685 | NodeKind::AsyncSuspendResumePartialFunction
686 | NodeKind::AsyncFunctionPointer
687 | NodeKind::CoroFunctionPointer
688 | NodeKind::CoroutineContinuationPrototype => Symbol::Async(AsyncSymbol::new(node)),
689
690 NodeKind::Macro
692 | NodeKind::FreestandingMacroExpansion
693 | NodeKind::MacroExpansionUniqueName
694 | NodeKind::AccessorAttachedMacroExpansion
695 | NodeKind::BodyAttachedMacroExpansion
696 | NodeKind::ConformanceAttachedMacroExpansion
697 | NodeKind::ExtensionAttachedMacroExpansion
698 | NodeKind::MemberAttachedMacroExpansion
699 | NodeKind::MemberAttributeAttachedMacroExpansion
700 | NodeKind::PeerAttachedMacroExpansion
701 | NodeKind::PreambleAttachedMacroExpansion => Symbol::Macro(MacroSymbol::new(node)),
702
703 NodeKind::AutoDiffFunction | NodeKind::DifferentiabilityWitness => {
705 Symbol::AutoDiff(AutoDiff::new(node))
706 }
707
708 NodeKind::Identifier => Symbol::Identifier(node),
710
711 _ => Symbol::Other(node),
713 }
714 }
715
716 pub fn raw(&self) -> Node<'ctx> {
718 match self {
719 Symbol::Function(f) => f.raw(),
720 Symbol::Constructor(c) => c.raw(),
721 Symbol::Destructor(d) => d.raw(),
722 Symbol::EnumCase(e) => e.raw(),
723 Symbol::Accessor(a) => a.raw(),
724 Symbol::Variable(v) => v.raw(),
725 Symbol::Closure(c) => c.raw(),
726 Symbol::Thunk(t) => t.raw(),
727 Symbol::Specialization(s) => s.specialization.raw(),
728 Symbol::WitnessTable(w) => w.raw(),
729 Symbol::Descriptor(d) => d.raw(),
730 Symbol::Metadata(m) => m.raw(),
731 Symbol::Type(t) => t.raw(),
732 Symbol::Attributed(a) => a.raw,
733 Symbol::DefaultArgument(d) => d.raw(),
734 Symbol::Outlined(o) => o.outlined.raw(),
735 Symbol::Async(a) => a.raw(),
736 Symbol::Macro(m) => m.raw(),
737 Symbol::AutoDiff(a) => a.raw(),
738 Symbol::Identifier(n) => *n,
739 Symbol::Suffixed(s) => s.inner.raw(),
740 Symbol::Other(n) => *n,
741 }
742 }
743
744 pub fn display(&self) -> String {
746 self.raw().to_string()
747 }
748
749 pub fn is_function(&self) -> bool {
751 matches!(self, Symbol::Function(_))
752 }
753
754 pub fn is_constructor(&self) -> bool {
756 matches!(self, Symbol::Constructor(_))
757 }
758
759 pub fn is_destructor(&self) -> bool {
761 matches!(self, Symbol::Destructor(_))
762 }
763
764 pub fn is_enum_case(&self) -> bool {
766 matches!(self, Symbol::EnumCase(_))
767 }
768
769 pub fn is_accessor(&self) -> bool {
771 matches!(self, Symbol::Accessor(_))
772 }
773
774 pub fn is_variable(&self) -> bool {
776 matches!(self, Symbol::Variable(_))
777 }
778
779 pub fn is_closure(&self) -> bool {
781 matches!(self, Symbol::Closure(_))
782 }
783
784 pub fn is_type(&self) -> bool {
786 matches!(self, Symbol::Type(_))
787 }
788
789 pub fn is_thunk(&self) -> bool {
791 matches!(self, Symbol::Thunk(_))
792 }
793
794 pub fn is_specialization(&self) -> bool {
796 matches!(self, Symbol::Specialization(_))
797 }
798
799 pub fn is_witness_table(&self) -> bool {
801 matches!(self, Symbol::WitnessTable(_))
802 }
803
804 pub fn is_descriptor(&self) -> bool {
806 matches!(self, Symbol::Descriptor(_))
807 }
808
809 pub fn is_metadata(&self) -> bool {
811 matches!(self, Symbol::Metadata(_))
812 }
813
814 pub fn is_attributed(&self) -> bool {
816 matches!(self, Symbol::Attributed(_))
817 }
818
819 pub fn is_default_argument(&self) -> bool {
821 matches!(self, Symbol::DefaultArgument(_))
822 }
823
824 pub fn as_function(&self) -> Option<&Function<'ctx>> {
826 match self {
827 Symbol::Function(f) => Some(f),
828 _ => None,
829 }
830 }
831
832 pub fn as_constructor(&self) -> Option<&Constructor<'ctx>> {
834 match self {
835 Symbol::Constructor(c) => Some(c),
836 _ => None,
837 }
838 }
839
840 pub fn as_destructor(&self) -> Option<&Destructor<'ctx>> {
842 match self {
843 Symbol::Destructor(d) => Some(d),
844 _ => None,
845 }
846 }
847
848 pub fn as_enum_case(&self) -> Option<&EnumCase<'ctx>> {
850 match self {
851 Symbol::EnumCase(e) => Some(e),
852 _ => None,
853 }
854 }
855
856 pub fn as_accessor(&self) -> Option<&Accessor<'ctx>> {
858 match self {
859 Symbol::Accessor(a) => Some(a),
860 _ => None,
861 }
862 }
863
864 pub fn as_variable(&self) -> Option<&Variable<'ctx>> {
866 match self {
867 Symbol::Variable(v) => Some(v),
868 _ => None,
869 }
870 }
871
872 pub fn as_closure(&self) -> Option<&Closure<'ctx>> {
874 match self {
875 Symbol::Closure(c) => Some(c),
876 _ => None,
877 }
878 }
879
880 pub fn as_type(&self) -> Option<&TypeRef<'ctx>> {
882 match self {
883 Symbol::Type(t) => Some(t),
884 _ => None,
885 }
886 }
887
888 pub fn as_thunk(&self) -> Option<&Thunk<'ctx>> {
890 match self {
891 Symbol::Thunk(t) => Some(t),
892 _ => None,
893 }
894 }
895
896 pub fn as_specialization(&self) -> Option<&SpecializedSymbol<'ctx>> {
898 match self {
899 Symbol::Specialization(s) => Some(s),
900 _ => None,
901 }
902 }
903
904 pub fn as_witness_table(&self) -> Option<&WitnessTable<'ctx>> {
906 match self {
907 Symbol::WitnessTable(w) => Some(w),
908 _ => None,
909 }
910 }
911
912 pub fn as_descriptor(&self) -> Option<&Descriptor<'ctx>> {
914 match self {
915 Symbol::Descriptor(d) => Some(d),
916 _ => None,
917 }
918 }
919
920 pub fn as_metadata(&self) -> Option<&Metadata<'ctx>> {
922 match self {
923 Symbol::Metadata(m) => Some(m),
924 _ => None,
925 }
926 }
927
928 pub fn as_attributed(&self) -> Option<&AttributedSymbol<'ctx>> {
930 match self {
931 Symbol::Attributed(a) => Some(a),
932 _ => None,
933 }
934 }
935
936 pub fn as_default_argument(&self) -> Option<&DefaultArgument<'ctx>> {
938 match self {
939 Symbol::DefaultArgument(d) => Some(d),
940 _ => None,
941 }
942 }
943
944 pub fn is_outlined(&self) -> bool {
946 matches!(self, Symbol::Outlined(_))
947 }
948
949 pub fn is_async(&self) -> bool {
951 matches!(self, Symbol::Async(_))
952 }
953
954 pub fn is_macro(&self) -> bool {
956 matches!(self, Symbol::Macro(_))
957 }
958
959 pub fn is_autodiff(&self) -> bool {
961 matches!(self, Symbol::AutoDiff(_))
962 }
963
964 pub fn as_outlined(&self) -> Option<&OutlinedSymbol<'ctx>> {
966 match self {
967 Symbol::Outlined(o) => Some(o),
968 _ => None,
969 }
970 }
971
972 pub fn as_async(&self) -> Option<&AsyncSymbol<'ctx>> {
974 match self {
975 Symbol::Async(a) => Some(a),
976 _ => None,
977 }
978 }
979
980 pub fn as_macro(&self) -> Option<&MacroSymbol<'ctx>> {
982 match self {
983 Symbol::Macro(m) => Some(m),
984 _ => None,
985 }
986 }
987
988 pub fn as_autodiff(&self) -> Option<&AutoDiff<'ctx>> {
990 match self {
991 Symbol::AutoDiff(a) => Some(a),
992 _ => None,
993 }
994 }
995}
996
997impl std::fmt::Display for Symbol<'_> {
998 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
999 write!(f, "{}", self.display())
1000 }
1001}
1002
1003#[derive(Clone, Copy)]
1005pub struct Variable<'ctx> {
1006 raw: Node<'ctx>,
1007}
1008
1009impl<'ctx> Variable<'ctx> {
1010 pub fn new(raw: Node<'ctx>) -> Self {
1012 Self { raw }
1013 }
1014
1015 pub fn raw(&self) -> Node<'ctx> {
1017 self.raw
1018 }
1019
1020 pub fn name(&self) -> Option<&'ctx str> {
1022 for child in self.raw.children() {
1023 if child.kind() == NodeKind::Identifier {
1024 return child.text();
1025 }
1026 }
1027 None
1028 }
1029
1030 pub fn module(&self) -> Option<&'ctx str> {
1032 for child in self.raw.children() {
1033 if child.kind() == NodeKind::Module {
1034 return child.text();
1035 }
1036 }
1037 for child in self.raw.children() {
1039 match child.kind() {
1040 NodeKind::Class | NodeKind::Structure | NodeKind::Enum | NodeKind::Extension => {
1041 for inner in child.descendants() {
1042 if inner.kind() == NodeKind::Module {
1043 return inner.text();
1044 }
1045 }
1046 }
1047 _ => {}
1048 }
1049 }
1050 None
1051 }
1052
1053 pub fn variable_type(&self) -> Option<TypeRef<'ctx>> {
1055 self.raw.extract_type_ref()
1056 }
1057
1058 pub fn context(&self) -> crate::context::SymbolContext<'ctx> {
1060 crate::context::extract_context(self.raw)
1061 }
1062}
1063
1064impl std::fmt::Debug for Variable<'_> {
1065 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1066 f.debug_struct("Variable")
1067 .field("name", &self.name())
1068 .field("module", &self.module())
1069 .field("type", &self.variable_type())
1070 .finish()
1071 }
1072}
1073
1074#[cfg(test)]
1075mod tests {
1076 use super::*;
1077
1078 #[test]
1079 fn test_parse_function() {
1080 let ctx = Context::new();
1081 let symbol = Symbol::parse(&ctx, "$s4main5helloSSyYaKF").unwrap();
1082 assert!(symbol.is_function());
1083 }
1084
1085 #[test]
1086 fn test_parse_variable() {
1087 let ctx = Context::new();
1088 let symbol = Symbol::parse(&ctx, "_Tv3foo3barSi").unwrap();
1090 assert!(symbol.is_variable());
1091 if let Symbol::Variable(var) = symbol {
1092 assert_eq!(var.name(), Some("bar"));
1093 assert_eq!(var.module(), Some("foo"));
1094 }
1095 }
1096
1097 #[test]
1098 fn test_parse_getter() {
1099 let ctx = Context::new();
1100 let symbol = Symbol::parse(&ctx, "_TF3foog3barSi").unwrap();
1102 assert!(symbol.is_accessor());
1103 }
1104
1105 #[test]
1106 fn test_parse_setter() {
1107 let ctx = Context::new();
1108 let symbol = Symbol::parse(&ctx, "_TF3foos3barSi").unwrap();
1110 assert!(symbol.is_accessor());
1111 }
1112
1113 #[test]
1114 fn test_symbol_display() {
1115 let ctx = Context::new();
1116 let symbol = Symbol::parse(&ctx, "$s4main5helloSSyYaKF").unwrap();
1117 let display = symbol.display();
1118 assert!(display.contains("hello"));
1119 }
1120
1121 #[test]
1122 fn test_symbol_as_methods() {
1123 let ctx = Context::new();
1124 let symbol = Symbol::parse(&ctx, "$s4main5helloSSyYaKF").unwrap();
1125 assert!(symbol.as_function().is_some());
1126 assert!(symbol.as_constructor().is_none());
1127 assert!(symbol.as_accessor().is_none());
1128 }
1129}