Skip to main content

palladium/lsp/
analysis.rs

1// Code analysis utilities for LSP
2// "Deep insights into your legendary code"
3
4use super::LanguageServer;
5use crate::ast::{Expr, Item, Program, Stmt, Type};
6use std::collections::{HashMap, HashSet};
7
8/// Code analysis results
9pub struct AnalysisResults {
10    /// Unused variables
11    pub unused_vars: HashSet<String>,
12    /// Unreachable code locations
13    pub unreachable_code: Vec<crate::errors::Span>,
14    /// Type mismatches
15    pub type_errors: Vec<TypeError>,
16    /// Missing imports
17    pub missing_imports: Vec<String>,
18}
19
20/// Type error information
21pub struct TypeError {
22    pub expected: Type,
23    pub found: Type,
24    pub span: crate::errors::Span,
25    pub message: String,
26}
27
28impl LanguageServer {
29    /// Perform semantic analysis on a program
30    pub fn analyze_program(&self, program: &Program) -> AnalysisResults {
31        let mut results = AnalysisResults {
32            unused_vars: HashSet::new(),
33            unreachable_code: Vec::new(),
34            type_errors: Vec::new(),
35            missing_imports: Vec::new(),
36        };
37
38        // Analyze each item
39        for item in &program.items {
40            self.analyze_item(item, &mut results);
41        }
42
43        results
44    }
45
46    /// Analyze an item
47    fn analyze_item(&self, item: &Item, results: &mut AnalysisResults) {
48        match item {
49            Item::Function(func) => {
50                let mut analyzer = FunctionAnalyzer::new();
51                analyzer.analyze_function(func, results);
52            }
53            Item::Trait(trait_def) => {
54                for method in &trait_def.methods {
55                    let mut analyzer = FunctionAnalyzer::new();
56                    analyzer.analyze_method(method, results);
57                }
58            }
59            Item::Impl(impl_block) => {
60                for method in &impl_block.methods {
61                    let mut analyzer = FunctionAnalyzer::new();
62                    analyzer.analyze_function(method, results);
63                }
64            }
65            _ => {}
66        }
67    }
68
69    /// Get semantic tokens for syntax highlighting
70    pub fn get_semantic_tokens(&self, ast: &Program) -> Vec<SemanticToken> {
71        let mut tokens = Vec::new();
72        let builder = SemanticTokenBuilder::new();
73
74        for item in &ast.items {
75            builder.process_item(item, &mut tokens);
76        }
77
78        tokens.sort_by_key(|t| (t.line, t.character));
79        tokens
80    }
81}
82
83/// Semantic token for syntax highlighting
84#[derive(Debug, Clone)]
85pub struct SemanticToken {
86    pub line: u32,
87    pub character: u32,
88    pub length: u32,
89    pub token_type: SemanticTokenType,
90    pub modifiers: Vec<SemanticTokenModifier>,
91}
92
93/// Semantic token types
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub enum SemanticTokenType {
96    Type,
97    Class,
98    Enum,
99    Interface,
100    Struct,
101    TypeParameter,
102    Parameter,
103    Variable,
104    Property,
105    EnumMember,
106    Function,
107    Method,
108    Macro,
109    Keyword,
110    Comment,
111    String,
112    Number,
113    Operator,
114}
115
116/// Semantic token modifiers
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118pub enum SemanticTokenModifier {
119    Declaration,
120    Definition,
121    Readonly,
122    Static,
123    Deprecated,
124    Abstract,
125    Async,
126    Modification,
127    Documentation,
128    DefaultLibrary,
129}
130
131/// Function analyzer
132struct FunctionAnalyzer {
133    declared_vars: HashMap<String, crate::errors::Span>,
134    used_vars: HashSet<String>,
135    has_return: bool,
136}
137
138impl FunctionAnalyzer {
139    fn new() -> Self {
140        Self {
141            declared_vars: HashMap::new(),
142            used_vars: HashSet::new(),
143            has_return: false,
144        }
145    }
146
147    fn analyze_function(&mut self, func: &crate::ast::Function, results: &mut AnalysisResults) {
148        // Add parameters to declared vars
149        for param in &func.params {
150            self.declared_vars.insert(
151                param.name.clone(),
152                crate::errors::Span {
153                    start: 0,
154                    end: 0,
155                    line: 0,
156                    column: 0,
157                },
158            );
159        }
160
161        // Analyze body
162        self.analyze_statements(&func.body, results);
163
164        // Check for unused variables
165        for var in self.declared_vars.keys() {
166            if !self.used_vars.contains(var) && !var.starts_with('_') {
167                results.unused_vars.insert(var.clone());
168            }
169        }
170
171        // Check for missing return
172        if func.return_type.is_some() && !self.has_return {
173            // TODO: Add error for missing return
174        }
175    }
176
177    fn analyze_method(&mut self, method: &crate::ast::TraitMethod, results: &mut AnalysisResults) {
178        // Add parameters to declared vars
179        for param in &method.params {
180            self.declared_vars.insert(
181                param.name.clone(),
182                crate::errors::Span {
183                    start: 0,
184                    end: 0,
185                    line: 0,
186                    column: 0,
187                },
188            );
189        }
190
191        // Analyze body
192        if let Some(body) = &method.body {
193            self.analyze_statements(body, results);
194        }
195    }
196
197    fn analyze_statements(&mut self, stmts: &[Stmt], results: &mut AnalysisResults) {
198        let mut unreachable = false;
199
200        for stmt in stmts {
201            if unreachable {
202                results.unreachable_code.push(self.get_statement_span(stmt));
203            }
204
205            match stmt {
206                Stmt::Let {
207                    name, value, span, ..
208                } => {
209                    self.declared_vars.insert(name.clone(), *span);
210                    self.analyze_expression(value);
211                }
212                Stmt::Return(_) => {
213                    self.has_return = true;
214                    unreachable = true;
215                }
216                Stmt::Expr(expr) => {
217                    self.analyze_expression(expr);
218                }
219                Stmt::If {
220                    condition,
221                    then_branch,
222                    else_branch,
223                    ..
224                } => {
225                    self.analyze_expression(condition);
226                    self.analyze_statements(then_branch, results);
227                    if let Some(else_branch) = else_branch {
228                        self.analyze_statements(else_branch, results);
229                    }
230                }
231                Stmt::While {
232                    condition, body, ..
233                } => {
234                    self.analyze_expression(condition);
235                    self.analyze_statements(body, results);
236                }
237                Stmt::For {
238                    var,
239                    iter,
240                    body,
241                    span,
242                    ..
243                } => {
244                    self.declared_vars.insert(var.clone(), *span);
245                    self.analyze_expression(iter);
246                    self.analyze_statements(body, results);
247                }
248                _ => {}
249            }
250        }
251    }
252
253    fn analyze_expression(&mut self, expr: &Expr) {
254        match expr {
255            Expr::Ident(name) => {
256                self.used_vars.insert(name.clone());
257            }
258            Expr::Call { func, args, .. } => {
259                self.analyze_expression(func);
260                for arg in args {
261                    self.analyze_expression(arg);
262                }
263            }
264            Expr::Binary { left, right, .. } => {
265                self.analyze_expression(left);
266                self.analyze_expression(right);
267            }
268            Expr::Unary { operand, .. } => {
269                self.analyze_expression(operand);
270            }
271            Expr::FieldAccess { object, .. } => {
272                self.analyze_expression(object);
273            }
274            Expr::Index { array, index, .. } => {
275                self.analyze_expression(array);
276                self.analyze_expression(index);
277            }
278            _ => {}
279        }
280    }
281
282    fn get_statement_span(&self, stmt: &Stmt) -> crate::errors::Span {
283        match stmt {
284            Stmt::Let { span, .. } => *span,
285            Stmt::Expr(expr) => self.get_expression_span(expr),
286            Stmt::Return(expr) => {
287                if let Some(expr) = expr {
288                    self.get_expression_span(expr)
289                } else {
290                    crate::errors::Span {
291                        start: 0,
292                        end: 0,
293                        line: 0,
294                        column: 0,
295                    }
296                }
297            }
298            Stmt::If { span, .. } => *span,
299            Stmt::While { span, .. } => *span,
300            Stmt::For { span, .. } => *span,
301            Stmt::Match { span, .. } => *span,
302            _ => crate::errors::Span {
303                start: 0,
304                end: 0,
305                line: 0,
306                column: 0,
307            },
308        }
309    }
310
311    fn get_expression_span(&self, expr: &Expr) -> crate::errors::Span {
312        match expr {
313            Expr::Ident(_) => crate::errors::Span {
314                start: 0,
315                end: 0,
316                line: 0,
317                column: 0,
318            },
319            Expr::Integer(_) => crate::errors::Span {
320                start: 0,
321                end: 0,
322                line: 0,
323                column: 0,
324            },
325            Expr::String(_) => crate::errors::Span {
326                start: 0,
327                end: 0,
328                line: 0,
329                column: 0,
330            },
331            Expr::Bool(_) => crate::errors::Span {
332                start: 0,
333                end: 0,
334                line: 0,
335                column: 0,
336            },
337            Expr::Call { span, .. } => *span,
338            Expr::Binary { span, .. } => *span,
339            Expr::Unary { span, .. } => *span,
340            Expr::FieldAccess { span, .. } => *span,
341            Expr::Index { span, .. } => *span,
342            Expr::ArrayLiteral { span, .. } => *span,
343            Expr::ArrayRepeat { span, .. } => *span,
344            Expr::StructLiteral { span, .. } => *span,
345            Expr::EnumConstructor { span, .. } => *span,
346            _ => crate::errors::Span {
347                start: 0,
348                end: 0,
349                line: 0,
350                column: 0,
351            },
352        }
353    }
354}
355
356/// Semantic token builder
357struct SemanticTokenBuilder;
358
359impl SemanticTokenBuilder {
360    fn new() -> Self {
361        Self
362    }
363
364    fn process_item(&self, item: &Item, tokens: &mut Vec<SemanticToken>) {
365        match item {
366            Item::Function(func) => {
367                // Function name
368                tokens.push(SemanticToken {
369                    line: func.span.start as u32,
370                    character: 0, // TODO: Calculate character offset
371                    length: func.name.len() as u32,
372                    token_type: SemanticTokenType::Function,
373                    modifiers: vec![SemanticTokenModifier::Declaration],
374                });
375
376                // Parameters
377                for param in &func.params {
378                    tokens.push(SemanticToken {
379                        line: func.span.start as u32,
380                        character: 0, // TODO: Calculate character offset
381                        length: param.name.len() as u32,
382                        token_type: SemanticTokenType::Parameter,
383                        modifiers: vec![],
384                    });
385                }
386            }
387            Item::Struct(struct_def) => {
388                // Struct name
389                tokens.push(SemanticToken {
390                    line: struct_def.span.start as u32,
391                    character: 0, // TODO: Calculate character offset
392                    length: struct_def.name.len() as u32,
393                    token_type: SemanticTokenType::Struct,
394                    modifiers: vec![SemanticTokenModifier::Declaration],
395                });
396            }
397            Item::Enum(enum_def) => {
398                // Enum name
399                tokens.push(SemanticToken {
400                    line: enum_def.span.start as u32,
401                    character: 0, // TODO: Calculate character offset
402                    length: enum_def.name.len() as u32,
403                    token_type: SemanticTokenType::Enum,
404                    modifiers: vec![SemanticTokenModifier::Declaration],
405                });
406            }
407            _ => {}
408        }
409    }
410}