Skip to main content

veryl_analyzer/
reference_table.rs

1use crate::AnalyzerError;
2use crate::generic_inference_table;
3use crate::namespace::Namespace;
4use crate::namespace_table;
5use crate::symbol::{Direction, GenericMap, Symbol, SymbolKind};
6use crate::symbol_path::{GenericSymbol, GenericSymbolPath, SymbolPath, SymbolPathNamespace};
7use crate::symbol_table;
8use crate::symbol_table::{ResolveError, ResolveErrorCause};
9use std::cell::RefCell;
10use veryl_parser::token_range::TokenRange;
11use veryl_parser::veryl_grammar_trait::{
12    ExpressionIdentifier, GenericArgIdentifier, HierarchicalIdentifier, Identifier,
13    InstParameterItem, InstPortItem, ModportItem, ScopedIdentifier, StructConstructorItem,
14};
15use veryl_parser::veryl_token::{Token, TokenSource, is_anonymous_text};
16
17#[derive(Clone, Debug)]
18pub enum ReferenceCandidate {
19    Identifier {
20        arg: Identifier,
21        namespace: Namespace,
22    },
23    HierarchicalIdentifier {
24        arg: HierarchicalIdentifier,
25        namespace: Namespace,
26    },
27    ScopedIdentifier {
28        arg: ScopedIdentifier,
29        namespace: Namespace,
30        in_import_declaration: bool,
31    },
32    ExpressionIdentifier {
33        arg: ExpressionIdentifier,
34        namespace: Namespace,
35    },
36    GenericArgIdentifier {
37        arg: GenericArgIdentifier,
38        namespace: Namespace,
39    },
40    ModportItem {
41        arg: ModportItem,
42        namespace: Namespace,
43    },
44    InstParameterItem {
45        arg: InstParameterItem,
46        namespace: Namespace,
47    },
48    InstPortItem {
49        arg: InstPortItem,
50        namespace: Namespace,
51    },
52    StructConstructorItem {
53        arg: StructConstructorItem,
54        r#type: ExpressionIdentifier,
55    },
56    NamedArgument {
57        arg: ExpressionIdentifier,
58        function: ExpressionIdentifier,
59    },
60}
61
62impl From<&Identifier> for ReferenceCandidate {
63    fn from(value: &Identifier) -> Self {
64        Self::Identifier {
65            arg: value.clone(),
66            namespace: namespace_table::get_default(),
67        }
68    }
69}
70
71impl From<&HierarchicalIdentifier> for ReferenceCandidate {
72    fn from(value: &HierarchicalIdentifier) -> Self {
73        Self::HierarchicalIdentifier {
74            arg: value.clone(),
75            namespace: namespace_table::get_default(),
76        }
77    }
78}
79
80impl From<(&ScopedIdentifier, bool)> for ReferenceCandidate {
81    fn from(value: (&ScopedIdentifier, bool)) -> Self {
82        Self::ScopedIdentifier {
83            arg: value.0.clone(),
84            namespace: namespace_table::get_default(),
85            in_import_declaration: value.1,
86        }
87    }
88}
89
90impl From<&ExpressionIdentifier> for ReferenceCandidate {
91    fn from(value: &ExpressionIdentifier) -> Self {
92        Self::ExpressionIdentifier {
93            arg: value.clone(),
94            namespace: namespace_table::get_default(),
95        }
96    }
97}
98
99impl From<&GenericArgIdentifier> for ReferenceCandidate {
100    fn from(value: &GenericArgIdentifier) -> Self {
101        Self::GenericArgIdentifier {
102            arg: value.clone(),
103            namespace: namespace_table::get_default(),
104        }
105    }
106}
107
108impl From<&ModportItem> for ReferenceCandidate {
109    fn from(value: &ModportItem) -> Self {
110        Self::ModportItem {
111            arg: value.clone(),
112            namespace: namespace_table::get_default(),
113        }
114    }
115}
116
117impl From<&InstParameterItem> for ReferenceCandidate {
118    fn from(value: &InstParameterItem) -> Self {
119        Self::InstParameterItem {
120            arg: value.clone(),
121            namespace: namespace_table::get_default(),
122        }
123    }
124}
125
126impl From<&InstPortItem> for ReferenceCandidate {
127    fn from(value: &InstPortItem) -> Self {
128        Self::InstPortItem {
129            arg: value.clone(),
130            namespace: namespace_table::get_default(),
131        }
132    }
133}
134
135#[derive(Default, Debug)]
136pub struct ReferenceTable {
137    candidates: Vec<ReferenceCandidate>,
138    errors: Vec<AnalyzerError>,
139}
140
141impl ReferenceTable {
142    pub fn new() -> Self {
143        Self::default()
144    }
145
146    pub fn add(&mut self, cand: ReferenceCandidate) {
147        self.candidates.push(cand);
148    }
149
150    fn push_resolve_error(
151        &mut self,
152        err: ResolveError,
153        token: &TokenRange,
154        generics_token: Option<&Token>,
155        struct_token: Option<&Token>,
156    ) {
157        if let Some(last_found) = err.last_found {
158            let name = last_found.token.to_string();
159            match err.cause {
160                ResolveErrorCause::NotFound(not_found) => {
161                    let is_generic_if = if let SymbolKind::Port(ref port) = last_found.kind {
162                        port.direction == Direction::Interface
163                    } else {
164                        false
165                    };
166
167                    if !is_generic_if {
168                        let member = format!("{not_found}");
169                        self.errors
170                            .push(AnalyzerError::unknown_member(&name, &member, token));
171                    }
172                }
173                ResolveErrorCause::Private => {
174                    if matches!(last_found.kind, SymbolKind::Namespace) {
175                        self.errors
176                            .push(AnalyzerError::private_namespace(&name, token));
177                    } else {
178                        self.errors
179                            .push(AnalyzerError::private_member(&name, token));
180                    }
181                }
182                ResolveErrorCause::Invisible => {
183                    self.errors
184                        .push(AnalyzerError::invisible_identifier(&name, token));
185                }
186            }
187        } else if let ResolveErrorCause::NotFound(not_found) = err.cause {
188            let name = format!("{not_found}");
189            if let Some(generics_token) = generics_token {
190                self.errors
191                    .push(AnalyzerError::unresolvable_generic_expression(
192                        &name,
193                        token,
194                        &generics_token.into(),
195                    ));
196            } else if is_anonymous_text(not_found) {
197                // AnonymousIdentifierUsage is handled at create_type_dag
198            } else if let Some(struct_token) = struct_token {
199                self.errors.push(AnalyzerError::unknown_member(
200                    &struct_token.text.to_string(),
201                    &name,
202                    token,
203                ));
204            } else {
205                self.errors
206                    .push(AnalyzerError::undefined_identifier(&name, token));
207            }
208        } else {
209            unreachable!();
210        }
211    }
212
213    fn check_pacakge_reference(&mut self, symbol: &Symbol, token_range: &TokenRange) {
214        if !matches!(symbol.kind, SymbolKind::Package(_)) {
215            return;
216        }
217
218        let base_token = token_range.end;
219        let package_token = symbol.token;
220        if let (
221            TokenSource::File {
222                path: package_file, ..
223            },
224            TokenSource::File {
225                path: base_file, ..
226            },
227        ) = (package_token.source, base_token.source)
228        {
229            let referecne_before_definition = package_file == base_file
230                && (package_token.line > base_token.line
231                    || package_token.line == base_token.line
232                        && package_token.column > base_token.column);
233            if referecne_before_definition {
234                self.errors.push(AnalyzerError::referring_before_definition(
235                    &package_token.to_string(),
236                    token_range,
237                ));
238            }
239        }
240    }
241
242    fn generic_symbol_path(
243        &mut self,
244        path: &GenericSymbolPath,
245        namespace: &Namespace,
246        in_import_declaration: bool,
247        generics_token: Option<&Token>,
248        generic_maps: Option<&Vec<GenericMap>>,
249    ) {
250        let mut path = path.clone();
251        let mut resolved_generic_maps = vec![];
252
253        let orig_len = path.len();
254        path.resolve_imported(namespace, generic_maps);
255
256        // Prefix paths added by `resolve_imported` have already been resolved.
257        // They should be skipped.
258        let prefix_len = path.len() - orig_len;
259        for i in prefix_len..path.len() {
260            let base_path = path.base_path(i);
261            match symbol_table::resolve((&base_path, namespace)) {
262                Ok(symbol) => {
263                    self.check_pacakge_reference(&symbol.found, &path.range);
264                    symbol_table::add_reference(symbol.found.id, &path.paths[0].base);
265
266                    // Check number of arguments
267                    let params = symbol.found.generic_parameters();
268
269                    let mut inference_attempted_failed = false;
270                    if i + 1 == path.paths.len() {
271                        use generic_inference_table::InferredApply;
272                        match generic_inference_table::apply_inferred_args(&mut path, &symbol.found)
273                        {
274                            InferredApply::Missing => inference_attempted_failed = true,
275                            InferredApply::Applied | InferredApply::NotApplicable => {}
276                        }
277                    }
278
279                    let n_args = path.paths[i].arguments.len();
280
281                    if in_import_declaration
282                        && !params.is_empty()
283                        && matches!(
284                            symbol.found.kind,
285                            SymbolKind::Function(_) | SymbolKind::Struct(_) | SymbolKind::Union(_)
286                        )
287                    {
288                        // Generic function, struct and union should be imorted as-is
289                        // but not as thier instances.
290                        // https://github.com/veryl-lang/veryl/issues/1619
291                        if n_args != 0 {
292                            self.errors.push(AnalyzerError::invalid_import(&path.range))
293                        }
294                        continue;
295                    }
296
297                    let match_artiy = if params.len() > n_args {
298                        params[n_args].1.default_value.is_some()
299                    } else {
300                        params.len() == n_args
301                    };
302                    if !match_artiy {
303                        if inference_attempted_failed {
304                            self.errors.push(AnalyzerError::generic_inference_failed(
305                                &path.paths[i].base.to_string(),
306                                &path.range,
307                            ));
308                        } else {
309                            self.errors.push(AnalyzerError::mismatch_generics_arity(
310                                &path.paths[i].base.to_string(),
311                                params.len(),
312                                n_args,
313                                &path.range,
314                            ));
315                        }
316                        continue;
317                    }
318
319                    if (params.len() + n_args) == 0 {
320                        continue;
321                    }
322
323                    let target_symbol = symbol.found;
324
325                    let mut args: Vec<_> = path.paths[i].arguments.drain(0..).collect();
326                    for param in params.iter().skip(n_args) {
327                        //  apply default value
328                        args.push(param.1.default_value.as_ref().unwrap().clone());
329                    }
330
331                    for arg in args.iter_mut() {
332                        arg.unalias();
333                        // Global function is emitted into the caller namespace.
334                        // So namespace expansion is not needed.
335                        if !target_symbol.is_global_function() {
336                            arg.append_namespace_path(namespace, &target_symbol.namespace);
337                        }
338                    }
339
340                    path.paths[i].arguments.append(&mut args);
341
342                    // To ensure generic instances are emitted in the correct order,
343                    // generic args must be processed before the base component is processed.
344                    for arg in &path.paths[i].arguments {
345                        self.generic_symbol_path(arg, namespace, false, None, None);
346                    }
347
348                    if path.is_generic_reference() {
349                        Self::add_generic_reference(&target_symbol, namespace, &path, i);
350                    } else {
351                        Self::insert_generic_instance(
352                            &path,
353                            i,
354                            namespace,
355                            &target_symbol,
356                            &mut resolved_generic_maps,
357                            None,
358                        );
359                    }
360                }
361                Err(err) => {
362                    let single_path = path.paths.len() == 1;
363                    if single_path && !path.is_resolvable() {
364                        return;
365                    }
366
367                    self.push_resolve_error(err, &path.range, generics_token, None);
368                }
369            }
370        }
371    }
372
373    fn insert_generic_instance(
374        path: &GenericSymbolPath,
375        ith: usize,
376        namespace: &Namespace,
377        target: &Symbol,
378        generic_maps: &mut Vec<GenericMap>,
379        affiliation_symbol: Option<&Symbol>,
380    ) {
381        let instance_path = &path.paths[ith];
382        let Some((token, symbol)) =
383            Self::create_generic_instance(instance_path, target, namespace, affiliation_symbol)
384        else {
385            return;
386        };
387
388        if let Some(ref id) = symbol_table::insert(&token, symbol.clone()) {
389            symbol_table::add_generic_instance(target.id, *id);
390        }
391
392        generic_maps.push(GenericMap {
393            id: None,
394            map: target.generic_table(&instance_path.arguments),
395        });
396        Self::insert_subordinate_generic_instances(namespace, target, &symbol, generic_maps);
397    }
398
399    fn create_generic_instance(
400        symbol: &GenericSymbol,
401        target: &Symbol,
402        namespace: &Namespace,
403        affiliation_symbol: Option<&Symbol>,
404    ) -> Option<(Token, Symbol)> {
405        if !target.is_global_function() {
406            symbol.get_generic_instance(target, affiliation_symbol)
407        } else if let Some(affiliation_symbol) = affiliation_symbol {
408            if affiliation_symbol.is_component(true) {
409                symbol.get_generic_instance(target, Some(affiliation_symbol))
410            } else {
411                symbol.get_generic_instance(
412                    target,
413                    affiliation_symbol.get_parent_component().as_ref(),
414                )
415            }
416        } else if let Some(namespace_symbol) = namespace.get_symbol() {
417            if namespace_symbol.is_component(true) {
418                symbol.get_generic_instance(target, Some(&namespace_symbol))
419            } else {
420                symbol
421                    .get_generic_instance(target, namespace_symbol.get_parent_component().as_ref())
422            }
423        } else {
424            symbol.get_generic_instance(target, None)
425        }
426    }
427
428    fn insert_subordinate_generic_instances(
429        namespace: &Namespace,
430        target: &Symbol,
431        inst_symbol: &Symbol,
432        generic_maps: &[GenericMap],
433    ) {
434        let is_global_func = target.is_global_function();
435        let mut subordinate_paths = if !is_global_func {
436            target.generic_references()
437        } else if let Some(paths) = symbol_table::get_reference_functions(target.id) {
438            paths
439        } else {
440            return;
441        };
442
443        if subordinate_paths.is_empty() {
444            return;
445        }
446
447        let target_namespace = &target.inner_namespace();
448        for path in &mut subordinate_paths {
449            // check recursive reference
450            if path.paths[0].base.text == target.token.text {
451                continue;
452            }
453
454            path.apply_map(generic_maps);
455            path.unalias();
456            path.append_namespace_path(namespace, &target.namespace);
457
458            if let Ok(path_symbol) = symbol_table::resolve((&path.generic_path(), target_namespace))
459            {
460                let ith = path.len() - 1;
461                if is_global_func {
462                    Self::insert_generic_instance(
463                        path,
464                        ith,
465                        namespace,
466                        &path_symbol.found,
467                        &mut generic_maps.to_vec(),
468                        None,
469                    );
470                } else {
471                    Self::insert_generic_instance(
472                        path,
473                        ith,
474                        target_namespace,
475                        &path_symbol.found,
476                        &mut generic_maps.to_vec(),
477                        Some(inst_symbol),
478                    );
479                }
480            }
481        }
482    }
483
484    fn add_generic_reference(
485        symbol: &Symbol,
486        namespace: &Namespace,
487        path: &GenericSymbolPath,
488        ith: usize,
489    ) {
490        fn get_parent_generic_component(namespace: &Namespace) -> Option<Symbol> {
491            let target = namespace.get_symbol()?;
492            if target.has_generic_paramters() {
493                Some(target)
494            } else {
495                get_parent_generic_component(&target.namespace)
496            }
497        }
498
499        let mut namespace = namespace.clone();
500        namespace.strip_anonymous_path();
501
502        let mut target = if let Some(target) = get_parent_generic_component(&namespace)
503            && !target.is_global_function()
504        {
505            target
506        } else {
507            return;
508        };
509        let path = path.slice(ith);
510
511        // existing generic maps means that the target symbol has
512        // already been processed.
513        // For this case, need to insert generic instance generated from
514        // the given path explicitly.
515        let generic_maps = target.generic_maps();
516        for map in generic_maps {
517            let affiliation_symbol = map.id.map(|id| symbol_table::get(id).unwrap());
518            let mut path = path.clone();
519            let ith = path.len() - 1;
520
521            let mut maps = vec![map];
522            path.apply_map(&maps);
523            path.append_namespace_path(&namespace, &symbol.namespace);
524
525            Self::insert_generic_instance(
526                &path,
527                ith,
528                &namespace,
529                symbol,
530                &mut maps,
531                affiliation_symbol.as_ref(),
532            );
533        }
534
535        let kind = match target.kind {
536            SymbolKind::Function(mut x) => {
537                x.generic_references.push(path);
538                SymbolKind::Function(x)
539            }
540            SymbolKind::Module(mut x) => {
541                x.generic_references.push(path);
542                SymbolKind::Module(x)
543            }
544            SymbolKind::Interface(mut x) => {
545                x.generic_references.push(path);
546                SymbolKind::Interface(x)
547            }
548            SymbolKind::Package(mut x) => {
549                x.generic_references.push(path);
550                SymbolKind::Package(x)
551            }
552            SymbolKind::Struct(mut x) => {
553                x.generic_references.push(path);
554                SymbolKind::Struct(x)
555            }
556            SymbolKind::Union(mut x) => {
557                x.generic_references.push(path);
558                SymbolKind::Union(x)
559            }
560            _ => return,
561        };
562
563        target.kind = kind;
564        symbol_table::update(target);
565    }
566
567    fn check_simple_identifier(
568        &mut self,
569        path: &SymbolPathNamespace,
570        default_namespace: Option<&Namespace>,
571        token: &TokenRange,
572        struct_token: Option<&Token>,
573    ) {
574        if let Some(default_namespace) = default_namespace {
575            namespace_table::set_default(&default_namespace.paths);
576        }
577
578        match symbol_table::resolve(path) {
579            Ok(symbol) => {
580                for id in symbol.full_path {
581                    symbol_table::add_reference(id, &token.beg);
582                }
583            }
584            Err(err) => {
585                self.push_resolve_error(err, token, None, struct_token);
586            }
587        }
588    }
589
590    fn check_array_member_access(
591        &mut self,
592        path: &GenericSymbolPath,
593        namespace: &Namespace,
594        selects_per_component: &[usize],
595    ) {
596        for i in 0..path.len().saturating_sub(1) {
597            let base_path = path.base_path(i);
598            if let Ok(symbol) = symbol_table::resolve((&base_path, namespace))
599                && let Some(r#type) = symbol.found.kind.get_type()
600            {
601                let array_dims = r#type.array.len();
602                let applied_selects = selects_per_component.get(i).copied().unwrap_or(0);
603                if applied_selects < array_dims {
604                    let member_name = if i + 1 < path.len() {
605                        path.paths[i + 1].base.to_string()
606                    } else {
607                        String::new()
608                    };
609                    self.errors.push(AnalyzerError::member_access_on_array(
610                        &symbol.found.token.to_string(),
611                        &member_name,
612                        array_dims,
613                        &path.range,
614                    ));
615                    return;
616                }
617            }
618        }
619    }
620
621    fn check_complex_identifier(
622        &mut self,
623        path: &GenericSymbolPath,
624        default_namespace: &Namespace,
625        token: &Token,
626        in_import_declaration: bool,
627    ) {
628        namespace_table::set_default(&default_namespace.paths);
629        let namespace = namespace_table::get(token.id).unwrap();
630        self.generic_symbol_path(path, &namespace, in_import_declaration, None, None);
631    }
632
633    pub fn apply(&mut self) -> Vec<AnalyzerError> {
634        symbol_table::suppress_cache_clear();
635        let candidates: Vec<_> = self.candidates.drain(0..).collect();
636
637        for x in &candidates {
638            match x {
639                ReferenceCandidate::Identifier { arg, namespace } => {
640                    self.check_simple_identifier(&arg.into(), Some(namespace), &arg.into(), None);
641                }
642                ReferenceCandidate::HierarchicalIdentifier { arg, namespace } => {
643                    let token = arg.identifier.identifier_token.token;
644                    let path: GenericSymbolPath = arg.into();
645                    self.check_complex_identifier(&path, namespace, &token, false);
646                    if !arg.hierarchical_identifier_list0.is_empty() {
647                        let ns = namespace_table::get(token.id).unwrap_or(namespace.clone());
648                        let mut selects = vec![0usize; path.len()];
649                        selects[0] = arg.hierarchical_identifier_list.len();
650                        for (j, member) in arg.hierarchical_identifier_list0.iter().enumerate() {
651                            if 1 + j < selects.len() {
652                                selects[1 + j] = member.hierarchical_identifier_list0_list.len();
653                            }
654                        }
655                        self.check_array_member_access(&path, &ns, &selects);
656                    }
657                }
658                ReferenceCandidate::ScopedIdentifier {
659                    arg,
660                    namespace,
661                    in_import_declaration,
662                } => {
663                    let token = arg.identifier().token;
664                    self.check_complex_identifier(
665                        &arg.into(),
666                        namespace,
667                        &token,
668                        *in_import_declaration,
669                    );
670                }
671                ReferenceCandidate::ExpressionIdentifier { arg, namespace } => {
672                    let token = arg.scoped_identifier.identifier().token;
673                    let path: GenericSymbolPath = arg.into();
674                    self.check_complex_identifier(&path, namespace, &token, false);
675                    if !arg.expression_identifier_list0.is_empty() {
676                        let ns = namespace_table::get(token.id).unwrap_or(namespace.clone());
677                        let scoped_len = arg.scoped_identifier.scoped_identifier_list.len() + 1;
678                        let mut selects = vec![0usize; path.len()];
679                        if scoped_len <= selects.len() {
680                            selects[scoped_len - 1] = arg.expression_identifier_list.len();
681                        }
682                        for (j, member) in arg.expression_identifier_list0.iter().enumerate() {
683                            if scoped_len + j < selects.len() {
684                                selects[scoped_len + j] =
685                                    member.expression_identifier_list0_list.len();
686                            }
687                        }
688                        self.check_array_member_access(&path, &ns, &selects);
689                    }
690                }
691                ReferenceCandidate::GenericArgIdentifier { arg, namespace } => {
692                    let token = arg.scoped_identifier.identifier().token;
693                    self.check_complex_identifier(&arg.into(), namespace, &token, false);
694                }
695                ReferenceCandidate::ModportItem { arg, namespace } => {
696                    let mut path: SymbolPathNamespace = arg.identifier.as_ref().into();
697                    path.pop_namespace();
698                    self.check_simple_identifier(&path, Some(namespace), &arg.into(), None);
699                }
700                ReferenceCandidate::InstParameterItem { arg, namespace } => {
701                    if arg.inst_parameter_item_opt.is_none() {
702                        // implicit port connection by name
703                        let identifier = arg.identifier.as_ref();
704                        self.check_simple_identifier(
705                            &identifier.into(),
706                            Some(namespace),
707                            &identifier.into(),
708                            None,
709                        );
710                    }
711                }
712                ReferenceCandidate::InstPortItem { arg, namespace } => {
713                    if arg.inst_port_item_opt.is_none() {
714                        // implicit port connection by name
715                        let identifier = arg.identifier.as_ref();
716                        self.check_simple_identifier(
717                            &identifier.into(),
718                            Some(namespace),
719                            &identifier.into(),
720                            None,
721                        );
722                    }
723                }
724                ReferenceCandidate::StructConstructorItem { arg, r#type } => {
725                    if let Ok(symbol) = symbol_table::resolve(r#type)
726                        && !matches!(symbol.found.kind, SymbolKind::SystemVerilog)
727                    {
728                        let identifier = arg.identifier.as_ref();
729
730                        let namespace = Self::get_struct_namespace(&symbol.found);
731                        let path: SymbolPathNamespace = (identifier, &namespace).into();
732
733                        self.check_simple_identifier(
734                            &path,
735                            None,
736                            &identifier.into(),
737                            Some(&symbol.found.token),
738                        );
739                    }
740                }
741                ReferenceCandidate::NamedArgument { arg, function } => {
742                    if let Ok(symbol) = symbol_table::resolve(function) {
743                        let func_symbol =
744                            if let SymbolKind::ModportFunctionMember(x) = &symbol.found.kind {
745                                symbol_table::get(x.function).unwrap()
746                            } else {
747                                (*symbol.found).clone()
748                            };
749                        let namespace = func_symbol.inner_namespace();
750                        let path: SymbolPath = arg.into();
751                        let path: SymbolPathNamespace = (&path, &namespace).into();
752                        self.check_simple_identifier(
753                            &path,
754                            None,
755                            &arg.into(),
756                            Some(&func_symbol.token),
757                        );
758                    }
759                }
760            }
761        }
762
763        symbol_table::resume_cache_clear();
764        self.errors.drain(0..).collect()
765    }
766
767    fn get_struct_namespace(symbol: &Symbol) -> Namespace {
768        match &symbol.kind {
769            SymbolKind::TypeDef(x) => {
770                let namespace = Some(&symbol.namespace);
771                if let Some((_, Some(symbol))) = x.r#type.trace_user_defined(namespace) {
772                    return Self::get_struct_namespace(&symbol);
773                }
774            }
775            SymbolKind::ProtoTypeDef(x) => {
776                if let Some(r#type) = &x.r#type {
777                    let namespace = Some(&symbol.namespace);
778                    if let Some((_, Some(symbol))) = r#type.trace_user_defined(namespace) {
779                        return Self::get_struct_namespace(&symbol);
780                    }
781                }
782            }
783            _ => {}
784        }
785        symbol.inner_namespace()
786    }
787}
788
789thread_local!(static REFERENCE_TABLE: RefCell<ReferenceTable> = RefCell::new(ReferenceTable::new()));
790
791pub fn add(cand: ReferenceCandidate) {
792    REFERENCE_TABLE.with(|f| f.borrow_mut().add(cand))
793}
794
795pub fn apply() -> Vec<AnalyzerError> {
796    REFERENCE_TABLE.with(|f| f.borrow_mut().apply())
797}