1use super::LanguageServer;
5use crate::ast::{Expr, Item, Program, Stmt, Type};
6use std::collections::{HashMap, HashSet};
7
8pub struct AnalysisResults {
10 pub unused_vars: HashSet<String>,
12 pub unreachable_code: Vec<crate::errors::Span>,
14 pub type_errors: Vec<TypeError>,
16 pub missing_imports: Vec<String>,
18}
19
20pub 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 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 for item in &program.items {
40 self.analyze_item(item, &mut results);
41 }
42
43 results
44 }
45
46 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 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#[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#[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#[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
131struct 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 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 self.analyze_statements(&func.body, results);
163
164 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 if func.return_type.is_some() && !self.has_return {
173 }
175 }
176
177 fn analyze_method(&mut self, method: &crate::ast::TraitMethod, results: &mut AnalysisResults) {
178 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 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
356struct 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 tokens.push(SemanticToken {
369 line: func.span.start as u32,
370 character: 0, length: func.name.len() as u32,
372 token_type: SemanticTokenType::Function,
373 modifiers: vec![SemanticTokenModifier::Declaration],
374 });
375
376 for param in &func.params {
378 tokens.push(SemanticToken {
379 line: func.span.start as u32,
380 character: 0, length: param.name.len() as u32,
382 token_type: SemanticTokenType::Parameter,
383 modifiers: vec![],
384 });
385 }
386 }
387 Item::Struct(struct_def) => {
388 tokens.push(SemanticToken {
390 line: struct_def.span.start as u32,
391 character: 0, 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 tokens.push(SemanticToken {
400 line: enum_def.span.start as u32,
401 character: 0, length: enum_def.name.len() as u32,
403 token_type: SemanticTokenType::Enum,
404 modifiers: vec![SemanticTokenModifier::Declaration],
405 });
406 }
407 _ => {}
408 }
409 }
410}