rusty_cpp/parser/
template_context.rs

1/// Template Context Tracking
2///
3/// This module tracks template type parameters (like T, U, V) to distinguish them
4/// from regular function calls during safety checking.
5///
6/// When we see `T x = ...` in a template, `T` is a type parameter, not an undeclared
7/// function. This module helps identify such cases.
8
9use std::collections::HashSet;
10
11#[derive(Debug, Clone, Default)]
12pub struct TemplateContext {
13    /// Type parameters in current template scope
14    /// e.g., for `template<typename T, typename U>`, this would contain {"T", "U"}
15    type_parameters: HashSet<String>,
16}
17
18impl TemplateContext {
19    /// Create a new empty template context
20    pub fn new() -> Self {
21        Self {
22            type_parameters: HashSet::new(),
23        }
24    }
25
26    /// Enter a template scope with the given type parameters
27    ///
28    /// # Example
29    /// ```
30    /// use rusty_cpp::parser::TemplateContext;
31    /// let mut ctx = TemplateContext::new();
32    /// ctx.enter_template(vec!["T".to_string(), "U".to_string()]);
33    /// assert!(ctx.is_type_parameter("T"));
34    /// ```
35    pub fn enter_template(&mut self, params: Vec<String>) {
36        self.type_parameters.extend(params);
37    }
38
39    /// Exit the current template scope, clearing all type parameters
40    pub fn exit_template(&mut self) {
41        self.type_parameters.clear();
42    }
43
44    /// Check if a name is a template type parameter
45    ///
46    /// # Arguments
47    /// * `name` - The identifier to check (e.g., "T", "U", "Value")
48    ///
49    /// # Returns
50    /// `true` if `name` is a known type parameter in current scope
51    pub fn is_type_parameter(&self, name: &str) -> bool {
52        self.type_parameters.contains(name)
53    }
54
55    /// Get all type parameters in current scope
56    pub fn get_type_parameters(&self) -> &HashSet<String> {
57        &self.type_parameters
58    }
59
60    /// Check if we're currently in a template scope
61    pub fn is_in_template(&self) -> bool {
62        !self.type_parameters.is_empty()
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    #[test]
71    fn test_empty_context() {
72        let ctx = TemplateContext::new();
73        assert!(!ctx.is_type_parameter("T"));
74        assert!(!ctx.is_in_template());
75    }
76
77    #[test]
78    fn test_single_type_parameter() {
79        let mut ctx = TemplateContext::new();
80        ctx.enter_template(vec!["T".to_string()]);
81
82        assert!(ctx.is_type_parameter("T"));
83        assert!(!ctx.is_type_parameter("U"));
84        assert!(ctx.is_in_template());
85    }
86
87    #[test]
88    fn test_multiple_type_parameters() {
89        let mut ctx = TemplateContext::new();
90        ctx.enter_template(vec![
91            "T".to_string(),
92            "U".to_string(),
93            "Value".to_string(),
94        ]);
95
96        assert!(ctx.is_type_parameter("T"));
97        assert!(ctx.is_type_parameter("U"));
98        assert!(ctx.is_type_parameter("Value"));
99        assert!(!ctx.is_type_parameter("NotAParam"));
100    }
101
102    #[test]
103    fn test_exit_template() {
104        let mut ctx = TemplateContext::new();
105        ctx.enter_template(vec!["T".to_string()]);
106        assert!(ctx.is_type_parameter("T"));
107
108        ctx.exit_template();
109        assert!(!ctx.is_type_parameter("T"));
110        assert!(!ctx.is_in_template());
111    }
112
113    #[test]
114    fn test_get_type_parameters() {
115        let mut ctx = TemplateContext::new();
116        ctx.enter_template(vec!["T".to_string(), "U".to_string()]);
117
118        let params = ctx.get_type_parameters();
119        assert_eq!(params.len(), 2);
120        assert!(params.contains("T"));
121        assert!(params.contains("U"));
122    }
123}