1use crate::declarations::{
37 cpp_template_parameter_kind, cpp_template_parameter_name, cpp_template_term, node_text,
38};
39use crate::graph::resolver::{
40 cpp_name_component_nodes, cpp_substitute_template_term, cpp_template_terms_equal,
41};
42use brokk_bifrost_core::analyzer::model::{CppTemplateParameterKind, CppTemplateTerm};
43use brokk_bifrost_core::analyzer::tree_walk::ParentIndex;
44use brokk_bifrost_core::hash::{HashMap, HashSet};
45use tree_sitter::Node;
46
47#[derive(Debug, Clone, PartialEq, Eq)]
49pub enum CppTemplateParameterShape {
50 Type,
51 Value {
56 type_term: CppTemplateTerm,
57 declarator: Option<CppTemplateTerm>,
58 },
59 Template(Vec<(CppTemplateParameterKind, bool)>),
63}
64
65#[derive(Debug, Clone, PartialEq, Eq)]
66pub struct CppTemplateParameter {
67 pub name: String,
69 pub variadic: bool,
70 pub shape: CppTemplateParameterShape,
71}
72
73impl CppTemplateParameter {
74 fn injected_argument(&self) -> CppTemplateTerm {
78 let parameter = CppTemplateTerm::Parameter(self.name.clone());
79 if self.variadic {
80 CppTemplateTerm::Node {
81 kind: "parameter_pack_expansion".to_owned(),
82 children: vec![
83 parameter,
84 CppTemplateTerm::Atom {
85 kind: "...".to_owned(),
86 text: "...".to_owned(),
87 },
88 ],
89 }
90 } else {
91 parameter
92 }
93 }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
98pub struct CppTemplateHead {
99 pub parameters: Vec<CppTemplateParameter>,
100 pub requires: Option<CppTemplateTerm>,
102}
103
104#[derive(Debug, Clone, PartialEq, Eq)]
107pub struct CppTemplateLevel {
108 pub name: String,
110 pub head: Option<CppTemplateHead>,
114 pub arguments: Option<Vec<CppTemplateTerm>>,
121}
122
123impl CppTemplateLevel {
124 fn is_bare(&self) -> bool {
125 self.head.is_none() && self.arguments.is_none()
126 }
127
128 fn effective_arguments(&self) -> Option<Vec<CppTemplateTerm>> {
129 self.arguments.clone().or_else(|| {
130 self.head.as_ref().map(|head| {
131 head.parameters
132 .iter()
133 .map(CppTemplateParameter::injected_argument)
134 .collect()
135 })
136 })
137 }
138}
139
140#[derive(Debug, Clone, PartialEq, Eq)]
143pub struct CppTemplateContext {
144 pub levels: Vec<CppTemplateLevel>,
145}
146
147#[derive(Debug, Clone, Default, PartialEq, Eq)]
150pub struct CppTemplateBinding {
151 right_to_left: HashMap<String, CppTemplateTerm>,
152 left: HashSet<String>,
153}
154
155impl CppTemplateBinding {
156 pub fn is_empty(&self) -> bool {
157 self.left.is_empty()
158 }
159
160 pub fn is_left_parameter(&self, name: &str) -> bool {
161 self.left.contains(name)
162 }
163
164 pub fn is_right_parameter(&self, name: &str) -> bool {
165 self.right_to_left.contains_key(name)
166 }
167
168 pub fn binds(&self, right: &str, left: &str) -> bool {
170 matches!(
171 self.right_to_left.get(right),
172 Some(CppTemplateTerm::Parameter(bound)) if bound == left
173 )
174 }
175
176 pub fn rename(&self, term: &CppTemplateTerm) -> Option<CppTemplateTerm> {
179 cpp_substitute_template_term(term, &self.right_to_left)
180 }
181
182 pub fn terms_agree(&self, left: &CppTemplateTerm, right: &CppTemplateTerm) -> bool {
184 self.rename(right)
185 .is_some_and(|renamed| cpp_template_terms_equal(left, &renamed))
186 }
187
188 fn bind(&mut self, right: &str, left: &str) {
189 self.left.insert(left.to_owned());
190 self.right_to_left.insert(
191 right.to_owned(),
192 CppTemplateTerm::Parameter(left.to_owned()),
193 );
194 }
195}
196
197#[derive(Debug, Clone, PartialEq, Eq)]
199pub enum CppTemplateReconciliation {
200 Equivalent(CppTemplateBinding),
202 Distinct,
206 Unsupported,
209}
210
211impl CppTemplateContext {
212 pub fn is_templated(&self) -> bool {
214 self.levels.iter().any(|level| !level.is_bare())
215 }
216
217 pub fn reconcile(&self, other: &CppTemplateContext) -> CppTemplateReconciliation {
224 let shared = self.levels.len().min(other.levels.len());
225 let (left_extra, left) = self.levels.split_at(self.levels.len() - shared);
226 let (right_extra, right) = other.levels.split_at(other.levels.len() - shared);
227 if !left_extra
228 .iter()
229 .chain(right_extra)
230 .all(CppTemplateLevel::is_bare)
231 {
232 return CppTemplateReconciliation::Unsupported;
233 }
234 let mut binding = CppTemplateBinding::default();
235 for (left_level, right_level) in left.iter().zip(right) {
236 if left_level.name != right_level.name {
237 return CppTemplateReconciliation::Unsupported;
238 }
239 match (&left_level.head, &right_level.head) {
240 (None, None) => {}
241 (Some(left_head), Some(right_head)) => {
242 if !heads_agree(left_head, right_head, &mut binding) {
243 return CppTemplateReconciliation::Distinct;
244 }
245 }
246 _ => return CppTemplateReconciliation::Distinct,
247 }
248 let agree = match (
249 left_level.effective_arguments(),
250 right_level.effective_arguments(),
251 ) {
252 (None, None) => true,
253 (Some(left_arguments), Some(right_arguments)) => {
254 left_arguments.len() == right_arguments.len()
255 && left_arguments
256 .iter()
257 .zip(&right_arguments)
258 .all(|(left, right)| binding.terms_agree(left, right))
259 }
260 _ => false,
261 };
262 if !agree {
263 return CppTemplateReconciliation::Distinct;
264 }
265 }
266 CppTemplateReconciliation::Equivalent(binding)
267 }
268}
269
270fn heads_agree(
275 left: &CppTemplateHead,
276 right: &CppTemplateHead,
277 binding: &mut CppTemplateBinding,
278) -> bool {
279 if left.parameters.len() != right.parameters.len() {
280 return false;
281 }
282 for (left_parameter, right_parameter) in left.parameters.iter().zip(&right.parameters) {
283 if left_parameter.variadic != right_parameter.variadic {
284 return false;
285 }
286 binding.bind(&right_parameter.name, &left_parameter.name);
287 let agree = match (&left_parameter.shape, &right_parameter.shape) {
288 (CppTemplateParameterShape::Type, CppTemplateParameterShape::Type) => true,
289 (
290 CppTemplateParameterShape::Value {
291 type_term: left_type,
292 declarator: left_declarator,
293 },
294 CppTemplateParameterShape::Value {
295 type_term: right_type,
296 declarator: right_declarator,
297 },
298 ) => {
299 binding.terms_agree(left_type, right_type)
300 && match (left_declarator, right_declarator) {
301 (None, None) => true,
302 (Some(left), Some(right)) => binding.terms_agree(left, right),
303 _ => false,
304 }
305 }
306 (
307 CppTemplateParameterShape::Template(left_kinds),
308 CppTemplateParameterShape::Template(right_kinds),
309 ) => left_kinds == right_kinds,
310 _ => false,
311 };
312 if !agree {
313 return false;
314 }
315 }
316 match (&left.requires, &right.requires) {
317 (None, None) => true,
318 (Some(left), Some(right)) => binding.terms_agree(left, right),
319 _ => false,
320 }
321}
322
323pub fn cpp_declaration_template_context(
331 node: Node<'_>,
332 source: &str,
333) -> Option<CppTemplateContext> {
334 let statement = declaration_statement(node)?;
335 let (own_heads, top) = direct_template_heads(statement);
336 let qualified = declaration_qualifier(statement);
337 let mut enclosing = Vec::new();
338 let mut current = top;
339 while let Some(parent) = current.parent() {
340 match parent.kind() {
341 "field_declaration_list" => {
342 let class = parent.parent()?;
343 if !is_class_specifier(class) {
344 return None;
345 }
346 enclosing.push(class);
347 current = class;
348 }
349 "template_declaration"
350 | "declaration"
351 | "field_declaration"
352 | "declaration_list"
353 | "namespace_definition"
354 | "linkage_specification"
355 | "preproc_if"
356 | "preproc_ifdef"
357 | "preproc_else"
358 | "preproc_elif"
359 | "preproc_elifdef" => current = parent,
360 "translation_unit" => break,
361 _ => return None,
362 }
363 }
364 let mut builder = ContextBuilder {
365 source,
366 ancestry: ParentIndex::unindexed(),
367 names: Vec::new(),
368 levels: Vec::new(),
369 };
370 for class in enclosing.into_iter().rev() {
371 let (heads, _) = direct_template_heads(class);
372 match heads.as_slice() {
373 [] => builder.push_class(class, None)?,
374 [head] => builder.push_class(class, Some(*head))?,
375 _ => return None,
376 }
377 }
378 if is_class_specifier(statement) {
379 match own_heads.as_slice() {
380 [] => builder.push_class(statement, None)?,
381 [head] => builder.push_class(statement, Some(*head))?,
382 _ => return None,
383 }
384 return Some(builder.finish());
385 }
386 match qualified {
387 Some(_) if !builder.levels.is_empty() => return None,
390 Some(qualifier) => builder.push_out_of_line(qualifier, &own_heads)?,
391 None => {
392 let head = match own_heads.as_slice() {
393 [] => None,
394 [head] => builder.head(*head)?,
395 _ => return None,
396 };
397 builder.levels.push(CppTemplateLevel {
398 name: String::new(),
399 head,
400 arguments: None,
401 });
402 }
403 }
404 if let Some(arguments) = declaration_terminal(statement)
408 .filter(|terminal| terminal.kind() == "template_function")
409 .and_then(|terminal| terminal.child_by_field_name("arguments"))
410 {
411 let arguments = builder.arguments(arguments);
412 builder.levels.last_mut()?.arguments = Some(arguments);
413 }
414 Some(builder.finish())
415}
416
417struct ContextBuilder<'a, 'tree> {
418 source: &'a str,
419 ancestry: ParentIndex<'tree>,
420 names: Vec<String>,
422 levels: Vec<CppTemplateLevel>,
423}
424
425impl<'tree> ContextBuilder<'_, 'tree> {
426 fn finish(self) -> CppTemplateContext {
427 CppTemplateContext {
428 levels: self.levels,
429 }
430 }
431
432 fn push_class(&mut self, class: Node<'tree>, head: Option<Node<'tree>>) -> Option<()> {
433 let head = match head {
434 Some(head) => self.head(head)?,
435 None => None,
436 };
437 let (name, arguments) = match class.child_by_field_name("name") {
438 None => (String::new(), None),
439 Some(name) if name.kind() == "template_type" => (
440 node_text(name.child_by_field_name("name")?, self.source).to_owned(),
441 Some(self.arguments(name.child_by_field_name("arguments")?)),
442 ),
443 Some(name) if name.kind() == "type_identifier" => {
444 (node_text(name, self.source).to_owned(), None)
445 }
446 Some(_) => return None,
449 };
450 self.levels.push(CppTemplateLevel {
451 name,
452 head,
453 arguments,
454 });
455 Some(())
456 }
457
458 fn push_out_of_line(&mut self, qualifier: Node<'tree>, heads: &[Node<'tree>]) -> Option<()> {
467 let mut components = cpp_name_component_nodes(qualifier)?;
468 components.pop()?;
469 let mut heads = heads.iter().copied().peekable();
470 for component in components {
471 let arguments = component
472 .parent()
473 .filter(|parent| {
474 matches!(parent.kind(), "template_type" | "template_function")
475 && parent.child_by_field_name("name") == Some(component)
476 })
477 .map(|template| template.child_by_field_name("arguments"));
478 let name = node_text(component, self.source).to_owned();
479 let Some(arguments) = arguments else {
480 self.levels.push(CppTemplateLevel {
481 name,
482 head: None,
483 arguments: None,
484 });
485 continue;
486 };
487 let arguments = arguments?;
488 let scope = self.names.len();
489 let head = match heads.peek().copied() {
490 Some(head) => {
491 let parsed = self.head(head)?;
492 let consumed = match &parsed {
493 None => true,
494 Some(parsed) => {
495 let introduced = parsed
496 .parameters
497 .iter()
498 .map(|parameter| parameter.name.as_str())
499 .collect::<HashSet<_>>();
500 self.arguments(arguments)
501 .iter()
502 .any(|term| term_names_any(term, &introduced))
503 }
504 };
505 if consumed {
506 heads.next();
507 parsed
508 } else {
509 self.names.truncate(scope);
510 None
511 }
512 }
513 None => None,
514 };
515 let arguments = Some(self.arguments(arguments));
516 self.levels.push(CppTemplateLevel {
517 name,
518 head,
519 arguments,
520 });
521 }
522 let own = match heads.next() {
523 Some(head) => self.head(head)?,
524 None => None,
525 };
526 if heads.next().is_some() {
527 return None;
528 }
529 self.levels.push(CppTemplateLevel {
530 name: String::new(),
531 head: own,
532 arguments: None,
533 });
534 Some(())
535 }
536
537 fn head(&mut self, template: Node<'tree>) -> Option<Option<CppTemplateHead>> {
540 let list = template.child_by_field_name("parameters")?;
541 let mut parameters = Vec::new();
542 let mut cursor = list.walk();
543 for (index, parameter) in list
544 .named_children(&mut cursor)
545 .filter(|child| !child.is_extra())
546 .enumerate()
547 {
548 if !matches!(
549 parameter.kind(),
550 "type_parameter_declaration"
551 | "optional_type_parameter_declaration"
552 | "variadic_type_parameter_declaration"
553 | "template_template_parameter_declaration"
554 | "parameter_declaration"
555 | "optional_parameter_declaration"
556 | "variadic_parameter_declaration"
557 ) {
558 return None;
559 }
560 let name = cpp_template_parameter_name(parameter, self.source)
561 .unwrap_or_else(|| format!("<anonymous:{}:{index}>", self.names.len()));
562 self.names.push(name.clone());
563 let variadic = matches!(
564 parameter.kind(),
565 "variadic_type_parameter_declaration" | "variadic_parameter_declaration"
566 );
567 let shape = match cpp_template_parameter_kind(parameter) {
568 CppTemplateParameterKind::Type => CppTemplateParameterShape::Type,
569 CppTemplateParameterKind::Template => {
570 let nested = parameter.child_by_field_name("parameters")?;
571 let mut cursor = nested.walk();
572 CppTemplateParameterShape::Template(
573 nested
574 .named_children(&mut cursor)
575 .filter(|child| !child.is_extra())
576 .map(|child| {
577 (
578 cpp_template_parameter_kind(child),
579 matches!(
580 child.kind(),
581 "variadic_type_parameter_declaration"
582 | "variadic_parameter_declaration"
583 ),
584 )
585 })
586 .collect(),
587 )
588 }
589 CppTemplateParameterKind::Value => CppTemplateParameterShape::Value {
590 type_term: self.term(parameter.child_by_field_name("type")?),
591 declarator: parameter
592 .child_by_field_name("declarator")
593 .filter(|declarator| {
594 !matches!(declarator.kind(), "identifier" | "variadic_declarator")
595 })
596 .map(|declarator| self.term(declarator)),
597 },
598 };
599 parameters.push(CppTemplateParameter {
600 name,
601 variadic,
602 shape,
603 });
604 }
605 let mut cursor = template.walk();
606 let requires = template
607 .named_children(&mut cursor)
608 .find(|child| child.kind() == "requires_clause")
609 .map(|clause| self.term(clause));
610 Some((!parameters.is_empty()).then_some(CppTemplateHead {
611 parameters,
612 requires,
613 }))
614 }
615
616 fn arguments(&self, list: Node<'tree>) -> Vec<CppTemplateTerm> {
617 let mut cursor = list.walk();
618 list.named_children(&mut cursor)
619 .filter(|argument| !argument.is_extra() && argument.kind() != "comment")
620 .map(|argument| self.term(argument))
621 .collect()
622 }
623
624 fn term(&self, node: Node<'tree>) -> CppTemplateTerm {
625 cpp_template_term(node, self.source, &self.names, &self.ancestry)
626 }
627}
628
629fn term_names_any(term: &CppTemplateTerm, names: &HashSet<&str>) -> bool {
630 let mut work = vec![term];
631 while let Some(term) = work.pop() {
632 match term {
633 CppTemplateTerm::Parameter(name) if names.contains(name.as_str()) => return true,
634 CppTemplateTerm::Node { children, .. } => work.extend(children),
635 CppTemplateTerm::Parameter(_) | CppTemplateTerm::Atom { .. } => {}
636 }
637 }
638 false
639}
640
641fn is_class_specifier(node: Node<'_>) -> bool {
642 matches!(
643 node.kind(),
644 "class_specifier" | "struct_specifier" | "union_specifier"
645 )
646}
647
648fn declaration_statement(node: Node<'_>) -> Option<Node<'_>> {
651 let mut current = node;
652 loop {
653 match current.kind() {
654 "function_definition" | "declaration" | "field_declaration" => return Some(current),
655 _ if is_class_specifier(current) => return Some(current),
656 "function_declarator"
657 | "pointer_declarator"
658 | "reference_declarator"
659 | "parenthesized_declarator"
660 | "attributed_declarator"
661 | "init_declarator" => current = current.parent()?,
662 _ => return None,
663 }
664 }
665}
666
667fn class_statement(class: Node<'_>) -> Node<'_> {
670 class
671 .parent()
672 .filter(|parent| {
673 matches!(parent.kind(), "declaration" | "field_declaration")
674 && parent.child_by_field_name("type") == Some(class)
675 })
676 .unwrap_or(class)
677}
678
679fn direct_template_heads(statement: Node<'_>) -> (Vec<Node<'_>>, Node<'_>) {
682 let statement = if is_class_specifier(statement) {
683 class_statement(statement)
684 } else {
685 statement
686 };
687 let mut heads = Vec::new();
688 let mut current = statement;
689 while let Some(parent) = current.parent() {
690 if parent.kind() != "template_declaration"
691 || parent.child_by_field_name("parameters") == Some(current)
692 {
693 break;
694 }
695 heads.push(parent);
696 current = parent;
697 }
698 heads.reverse();
699 (heads, current)
700}
701
702fn declaration_qualifier(statement: Node<'_>) -> Option<Node<'_>> {
704 if is_class_specifier(statement) {
705 return None;
706 }
707 let mut current = statement.child_by_field_name("declarator")?;
708 loop {
709 match current.kind() {
710 "qualified_identifier" => return Some(current),
711 "identifier" | "field_identifier" | "operator_name" | "destructor_name"
712 | "template_function" => return None,
713 _ => {
714 current = current
715 .child_by_field_name("declarator")
716 .or_else(|| current.named_child(0))?;
717 }
718 }
719 }
720}
721
722fn declaration_terminal(statement: Node<'_>) -> Option<Node<'_>> {
725 if is_class_specifier(statement) {
726 return None;
727 }
728 let mut current = statement.child_by_field_name("declarator")?;
729 loop {
730 match current.kind() {
731 "qualified_identifier" => current = current.child_by_field_name("name")?,
732 "identifier" | "field_identifier" | "operator_name" | "destructor_name"
733 | "template_function" => return Some(current),
734 _ => {
735 current = current
736 .child_by_field_name("declarator")
737 .or_else(|| current.named_child(0))?;
738 }
739 }
740 }
741}
742
743#[cfg(test)]
744mod tests {
745 use super::*;
746
747 const DECLARATIONS: &str = r#"namespace n {
748template<class T> struct Box {
749 void put(T);
750 template<class U> void take(U);
751};
752template<class T> struct Box<T*> {
753 void put(T*);
754};
755template<> struct Box<int> {
756 void exact();
757};
758template<class T, class U> struct Pair {
759 void pair();
760};
761template<int N> struct Fixed {
762 void reset();
763};
764template<class... Ts> struct Pack {
765 void pack();
766};
767template<class T> requires Ready<T> struct Gate {
768 void open();
769};
770void make();
771}
772"#;
773
774 const DEFINITIONS: &str = r#"namespace n {
775template<typename U> void Box<U>::put(U) {}
776template<class T> template<class W> void Box<T>::take(W) {}
777template<class T> void Box<T*>::put(T*) {}
778void Box<int>::exact() {}
779template<class T> void Pair<T>::pair() {}
780template<long N> void Fixed<N>::reset() {}
781template<int M> void Fixed<M>::reset() {}
782template<class... Us> void Pack<Us...>::pack() {}
783template<class T> void Pack<T>::pack() {}
784template<class U> requires Ready<U> void Gate<U>::open() {}
785template<class U> void Gate<U>::open() {}
786template<> void make<int>() {}
787using Exact = Box<int>;
788void Exact::exact() {}
789}
790"#;
791
792 fn context_of(source: &str, needle: &str) -> CppTemplateContext {
793 let tree = crate::diagnostics::parse_cpp_tree(source);
794 assert!(!tree.root_node().has_error(), "fixture must parse cleanly");
795 let start = source.find(needle).expect("needle");
796 let mut node = tree
797 .root_node()
798 .descendant_for_byte_range(start, start + needle.len())
799 .expect("needle node");
800 while !matches!(
801 node.kind(),
802 "function_definition" | "field_declaration" | "declaration" | "template_declaration"
803 ) {
804 node = node.parent().expect("declaration ancestor");
805 }
806 while node.kind() == "template_declaration" {
807 node = node
808 .named_child(node.named_child_count() - 1)
809 .expect("templated declaration");
810 }
811 cpp_declaration_template_context(node, source)
812 .unwrap_or_else(|| panic!("no template context for {needle}"))
813 }
814
815 #[test]
823 fn reconcile_matches_heads_and_owner_arguments_structurally() {
824 use CppTemplateReconciliation::{Distinct, Unsupported};
825 let cases = [
826 ("put(T);", "Box<U>::put(U)", Some(true)),
827 ("take(U)", "Box<T>::take(W)", Some(true)),
828 ("put(T*)", "Box<T*>::put(T*)", Some(true)),
829 ("put(T);", "Box<T*>::put(T*)", Some(false)),
830 ("exact();", "Box<int>::exact()", Some(true)),
831 ("put(T);", "Box<int>::exact()", Some(false)),
832 ("pair();", "Pair<T>::pair()", Some(false)),
833 ("reset();", "Fixed<N>::reset()", Some(false)),
834 ("reset();", "Fixed<M>::reset()", Some(true)),
835 ("pack();", "Pack<Us...>::pack()", Some(true)),
836 ("pack();", "Pack<T>::pack()", Some(false)),
837 ("open();", "Ready<U> void Gate<U>::open()", Some(true)),
838 ("open();", "<class U> void Gate<U>::open()", Some(false)),
839 ("make();", "make<int>()", Some(false)),
840 ("exact();", "Exact::exact()", None),
841 ];
842 let mut mismatches = Vec::new();
843 for (declaration, definition, expected) in cases {
844 let left = context_of(DECLARATIONS, declaration);
845 let right = context_of(DEFINITIONS, definition);
846 let forward = left.reconcile(&right);
847 let inverse = right.reconcile(&left);
848 let verdict = |reconciliation: &CppTemplateReconciliation| match reconciliation {
849 CppTemplateReconciliation::Equivalent(_) => Some(true),
850 Distinct => Some(false),
851 Unsupported => None,
852 };
853 if verdict(&forward) != expected || verdict(&inverse) != expected {
854 mismatches.push((declaration, definition, forward, inverse));
855 }
856 }
857 assert!(mismatches.is_empty(), "{mismatches:#?}");
858 }
859}