Skip to main content

rustlens_lib/analyzer/
types.rs

1//! Type definitions for analyzed Rust code items
2
3use std::fmt;
4use std::path::PathBuf;
5
6/// Source location information
7#[derive(Debug, Clone, Default)]
8pub struct SourceLocation {
9    pub file: Option<PathBuf>,
10    pub line: Option<usize>,
11    pub column: Option<usize>,
12}
13
14impl SourceLocation {
15    pub fn new(file: PathBuf, line: usize) -> Self {
16        Self {
17            file: Some(file),
18            line: Some(line),
19            column: None,
20        }
21    }
22}
23
24impl fmt::Display for SourceLocation {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        match (&self.file, self.line) {
27            (Some(file), Some(line)) => write!(f, "{}:{}", file.display(), line),
28            (Some(file), None) => write!(f, "{}", file.display()),
29            _ => write!(f, "unknown"),
30        }
31    }
32}
33
34/// Visibility of a Rust item
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
36pub enum Visibility {
37    Public,
38    Crate,
39    Super,
40    SelfOnly,
41    #[default]
42    Private,
43}
44
45impl fmt::Display for Visibility {
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        match self {
48            Visibility::Public => write!(f, "pub"),
49            Visibility::Crate => write!(f, "pub(crate)"),
50            Visibility::Super => write!(f, "pub(super)"),
51            Visibility::SelfOnly => write!(f, "pub(self)"),
52            Visibility::Private => write!(f, ""),
53        }
54    }
55}
56
57/// Analyzed item from Rust source code
58#[derive(Debug, Clone)]
59pub enum AnalyzedItem {
60    Function(FunctionInfo),
61    Struct(StructInfo),
62    Enum(EnumInfo),
63    Trait(TraitInfo),
64    Impl(ImplInfo),
65    Module(ModuleInfo),
66    TypeAlias(TypeAliasInfo),
67    Const(ConstInfo),
68    Static(StaticInfo),
69}
70
71impl AnalyzedItem {
72    pub fn name(&self) -> &str {
73        match self {
74            AnalyzedItem::Function(f) => &f.name,
75            AnalyzedItem::Struct(s) => &s.name,
76            AnalyzedItem::Enum(e) => &e.name,
77            AnalyzedItem::Trait(t) => &t.name,
78            AnalyzedItem::Impl(i) => &i.self_ty,
79            AnalyzedItem::Module(m) => &m.name,
80            AnalyzedItem::TypeAlias(t) => &t.name,
81            AnalyzedItem::Const(c) => &c.name,
82            AnalyzedItem::Static(s) => &s.name,
83        }
84    }
85
86    pub fn kind(&self) -> &'static str {
87        match self {
88            AnalyzedItem::Function(_) => "fn",
89            AnalyzedItem::Struct(_) => "struct",
90            AnalyzedItem::Enum(_) => "enum",
91            AnalyzedItem::Trait(_) => "trait",
92            AnalyzedItem::Impl(_) => "impl",
93            AnalyzedItem::Module(_) => "mod",
94            AnalyzedItem::TypeAlias(_) => "type",
95            AnalyzedItem::Const(_) => "const",
96            AnalyzedItem::Static(_) => "static",
97        }
98    }
99
100    pub fn visibility(&self) -> Option<Visibility> {
101        match self {
102            AnalyzedItem::Function(f) => Some(f.visibility),
103            AnalyzedItem::Struct(s) => Some(s.visibility),
104            AnalyzedItem::Enum(e) => Some(e.visibility),
105            AnalyzedItem::Trait(t) => Some(t.visibility),
106            AnalyzedItem::Impl(_) => None,
107            AnalyzedItem::Module(m) => Some(m.visibility),
108            AnalyzedItem::TypeAlias(t) => Some(t.visibility),
109            AnalyzedItem::Const(c) => Some(c.visibility),
110            AnalyzedItem::Static(s) => Some(s.visibility),
111        }
112    }
113
114    pub fn documentation(&self) -> Option<&str> {
115        match self {
116            AnalyzedItem::Function(f) => f.documentation.as_deref(),
117            AnalyzedItem::Struct(s) => s.documentation.as_deref(),
118            AnalyzedItem::Enum(e) => e.documentation.as_deref(),
119            AnalyzedItem::Trait(t) => t.documentation.as_deref(),
120            AnalyzedItem::Impl(_) => None,
121            AnalyzedItem::Module(m) => m.documentation.as_deref(),
122            AnalyzedItem::TypeAlias(t) => t.documentation.as_deref(),
123            AnalyzedItem::Const(c) => c.documentation.as_deref(),
124            AnalyzedItem::Static(s) => s.documentation.as_deref(),
125        }
126    }
127
128    pub fn source_location(&self) -> Option<&SourceLocation> {
129        match self {
130            AnalyzedItem::Function(f) => Some(&f.source_location),
131            AnalyzedItem::Struct(s) => Some(&s.source_location),
132            AnalyzedItem::Enum(e) => Some(&e.source_location),
133            AnalyzedItem::Trait(t) => Some(&t.source_location),
134            AnalyzedItem::Impl(i) => Some(&i.source_location),
135            AnalyzedItem::Module(m) => Some(&m.source_location),
136            AnalyzedItem::TypeAlias(t) => Some(&t.source_location),
137            AnalyzedItem::Const(c) => Some(&c.source_location),
138            AnalyzedItem::Static(s) => Some(&s.source_location),
139        }
140    }
141
142    /// Get the module path for this item (e.g., ["serde", "de"])
143    pub fn module_path(&self) -> &[String] {
144        match self {
145            AnalyzedItem::Function(f) => &f.module_path,
146            AnalyzedItem::Struct(s) => &s.module_path,
147            AnalyzedItem::Enum(e) => &e.module_path,
148            AnalyzedItem::Trait(t) => &t.module_path,
149            AnalyzedItem::Impl(i) => &i.module_path,
150            AnalyzedItem::Module(m) => &m.module_path,
151            AnalyzedItem::TypeAlias(t) => &t.module_path,
152            AnalyzedItem::Const(c) => &c.module_path,
153            AnalyzedItem::Static(s) => &s.module_path,
154        }
155    }
156
157    /// Get fully qualified path (e.g., "serde::de::Deserialize")
158    pub fn qualified_name(&self) -> String {
159        let path = self.module_path();
160        if path.is_empty() {
161            self.name().to_string()
162        } else {
163            format!("{}::{}", path.join("::"), self.name())
164        }
165    }
166
167    /// Get full definition as code string
168    pub fn definition(&self) -> String {
169        match self {
170            AnalyzedItem::Function(f) => f.signature.clone(),
171            AnalyzedItem::Struct(s) => s.full_definition(),
172            AnalyzedItem::Enum(e) => e.full_definition(),
173            AnalyzedItem::Trait(t) => t.full_definition(),
174            AnalyzedItem::Impl(i) => i.full_definition(),
175            AnalyzedItem::Module(m) => format!("mod {}", m.name),
176            AnalyzedItem::TypeAlias(t) => format!("type {} = {}", t.name, t.ty),
177            AnalyzedItem::Const(c) => format!("const {}: {}", c.name, c.ty),
178            AnalyzedItem::Static(s) => {
179                let mut_str = if s.is_mut { "mut " } else { "" };
180                format!("static {}{}: {}", mut_str, s.name, s.ty)
181            }
182        }
183    }
184}
185
186/// Information about a function
187#[derive(Debug, Clone)]
188pub struct FunctionInfo {
189    pub name: String,
190    pub signature: String,
191    pub visibility: Visibility,
192    pub is_async: bool,
193    pub is_const: bool,
194    pub is_unsafe: bool,
195    pub generics: Vec<String>,
196    pub parameters: Vec<Parameter>,
197    pub return_type: Option<String>,
198    pub documentation: Option<String>,
199    pub attributes: Vec<String>,
200    pub where_clause: Option<String>,
201    pub source_location: SourceLocation,
202    /// Module path for fully qualified naming (e.g., ["serde", "de"])
203    pub module_path: Vec<String>,
204}
205
206/// Function parameter
207#[derive(Debug, Clone)]
208pub struct Parameter {
209    pub name: String,
210    pub ty: String,
211    pub is_self: bool,
212    pub is_mut: bool,
213    pub is_ref: bool,
214}
215
216impl fmt::Display for Parameter {
217    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218        if self.is_self {
219            if self.is_ref && self.is_mut {
220                write!(f, "&mut self")
221            } else if self.is_ref {
222                write!(f, "&self")
223            } else if self.is_mut {
224                write!(f, "mut self")
225            } else {
226                write!(f, "self")
227            }
228        } else {
229            write!(f, "{}: {}", self.name, self.ty)
230        }
231    }
232}
233
234/// Information about a struct
235#[derive(Debug, Clone)]
236pub struct StructInfo {
237    pub name: String,
238    pub visibility: Visibility,
239    pub generics: Vec<String>,
240    pub fields: Vec<Field>,
241    pub kind: StructKind,
242    pub documentation: Option<String>,
243    pub derives: Vec<String>,
244    pub attributes: Vec<String>,
245    pub where_clause: Option<String>,
246    pub source_location: SourceLocation,
247    /// Module path for fully qualified naming
248    pub module_path: Vec<String>,
249}
250
251impl StructInfo {
252    pub fn full_definition(&self) -> String {
253        let vis = if self.visibility == Visibility::Public {
254            "pub "
255        } else {
256            ""
257        };
258        let generics = if self.generics.is_empty() {
259            String::new()
260        } else {
261            format!("<{}>", self.generics.join(", "))
262        };
263
264        match self.kind {
265            StructKind::Named => {
266                let fields: Vec<String> = self
267                    .fields
268                    .iter()
269                    .map(|f| {
270                        let fvis = if f.visibility == Visibility::Public {
271                            "pub "
272                        } else {
273                            ""
274                        };
275                        format!("    {}{}: {}", fvis, f.name, f.ty)
276                    })
277                    .collect();
278                format!(
279                    "{}struct {}{} {{\n{}\n}}",
280                    vis,
281                    self.name,
282                    generics,
283                    fields.join(",\n")
284                )
285            }
286            StructKind::Tuple => {
287                let fields: Vec<String> = self
288                    .fields
289                    .iter()
290                    .map(|f| {
291                        let fvis = if f.visibility == Visibility::Public {
292                            "pub "
293                        } else {
294                            ""
295                        };
296                        format!("{}{}", fvis, f.ty)
297                    })
298                    .collect();
299                format!(
300                    "{}struct {}{}({});",
301                    vis,
302                    self.name,
303                    generics,
304                    fields.join(", ")
305                )
306            }
307            StructKind::Unit => format!("{}struct {}{};", vis, self.name, generics),
308        }
309    }
310}
311
312#[derive(Debug, Clone, Copy, PartialEq, Eq)]
313pub enum StructKind {
314    Named,
315    Tuple,
316    Unit,
317}
318
319/// Struct/enum field
320#[derive(Debug, Clone)]
321pub struct Field {
322    pub name: String,
323    pub ty: String,
324    pub visibility: Visibility,
325    pub documentation: Option<String>,
326}
327
328/// Information about an enum
329#[derive(Debug, Clone)]
330pub struct EnumInfo {
331    pub name: String,
332    pub visibility: Visibility,
333    pub generics: Vec<String>,
334    pub variants: Vec<Variant>,
335    pub documentation: Option<String>,
336    pub derives: Vec<String>,
337    pub attributes: Vec<String>,
338    pub where_clause: Option<String>,
339    pub source_location: SourceLocation,
340    /// Module path for fully qualified naming
341    pub module_path: Vec<String>,
342}
343
344impl EnumInfo {
345    pub fn full_definition(&self) -> String {
346        let vis = if self.visibility == Visibility::Public {
347            "pub "
348        } else {
349            ""
350        };
351        let generics = if self.generics.is_empty() {
352            String::new()
353        } else {
354            format!("<{}>", self.generics.join(", "))
355        };
356
357        let variants: Vec<String> = self
358            .variants
359            .iter()
360            .map(|v| {
361                let fields = match &v.fields {
362                    VariantFields::Named(fields) => {
363                        let f: Vec<_> = fields
364                            .iter()
365                            .map(|f| format!("{}: {}", f.name, f.ty))
366                            .collect();
367                        format!(" {{ {} }}", f.join(", "))
368                    }
369                    VariantFields::Unnamed(types) => format!("({})", types.join(", ")),
370                    VariantFields::Unit => String::new(),
371                };
372                format!("    {}{}", v.name, fields)
373            })
374            .collect();
375
376        format!(
377            "{}enum {}{} {{\n{}\n}}",
378            vis,
379            self.name,
380            generics,
381            variants.join(",\n")
382        )
383    }
384}
385
386/// Enum variant
387#[derive(Debug, Clone)]
388pub struct Variant {
389    pub name: String,
390    pub fields: VariantFields,
391    pub discriminant: Option<String>,
392    pub documentation: Option<String>,
393}
394
395#[derive(Debug, Clone)]
396pub enum VariantFields {
397    Named(Vec<Field>),
398    Unnamed(Vec<String>),
399    Unit,
400}
401
402/// Information about a trait
403#[derive(Debug, Clone)]
404pub struct TraitInfo {
405    pub name: String,
406    pub visibility: Visibility,
407    pub generics: Vec<String>,
408    pub supertraits: Vec<String>,
409    pub methods: Vec<TraitMethod>,
410    pub associated_types: Vec<AssociatedType>,
411    pub associated_consts: Vec<AssociatedConst>,
412    pub documentation: Option<String>,
413    pub is_unsafe: bool,
414    pub is_auto: bool,
415    pub where_clause: Option<String>,
416    pub source_location: SourceLocation,
417    /// Module path for fully qualified naming
418    pub module_path: Vec<String>,
419}
420
421impl TraitInfo {
422    pub fn full_definition(&self) -> String {
423        let vis = if self.visibility == Visibility::Public {
424            "pub "
425        } else {
426            ""
427        };
428        let unsafe_str = if self.is_unsafe { "unsafe " } else { "" };
429        let auto_str = if self.is_auto { "auto " } else { "" };
430        let generics = if self.generics.is_empty() {
431            String::new()
432        } else {
433            format!("<{}>", self.generics.join(", "))
434        };
435        let bounds = if self.supertraits.is_empty() {
436            String::new()
437        } else {
438            format!(": {}", self.supertraits.join(" + "))
439        };
440
441        let mut items = Vec::new();
442        for at in &self.associated_types {
443            items.push(format!("    type {};", at.name));
444        }
445        for method in &self.methods {
446            items.push(format!("    {};", method.signature));
447        }
448
449        format!(
450            "{}{}{}trait {}{}{} {{\n{}\n}}",
451            vis,
452            unsafe_str,
453            auto_str,
454            self.name,
455            generics,
456            bounds,
457            items.join("\n")
458        )
459    }
460}
461
462/// Trait method signature
463#[derive(Debug, Clone)]
464pub struct TraitMethod {
465    pub name: String,
466    pub signature: String,
467    pub has_default: bool,
468    pub is_async: bool,
469    pub documentation: Option<String>,
470}
471
472/// Associated type in a trait
473#[derive(Debug, Clone)]
474pub struct AssociatedType {
475    pub name: String,
476    pub bounds: Vec<String>,
477    pub default: Option<String>,
478}
479
480/// Associated const in a trait
481#[derive(Debug, Clone)]
482pub struct AssociatedConst {
483    pub name: String,
484    pub ty: String,
485    pub default: Option<String>,
486}
487
488/// Information about an impl block
489#[derive(Debug, Clone)]
490pub struct ImplInfo {
491    pub self_ty: String,
492    pub trait_name: Option<String>,
493    pub generics: Vec<String>,
494    pub methods: Vec<FunctionInfo>,
495    pub is_unsafe: bool,
496    pub is_negative: bool,
497    pub where_clause: Option<String>,
498    pub source_location: SourceLocation,
499    /// Module path for fully qualified naming
500    pub module_path: Vec<String>,
501}
502
503impl ImplInfo {
504    pub fn full_definition(&self) -> String {
505        let unsafe_str = if self.is_unsafe { "unsafe " } else { "" };
506        let negative_str = if self.is_negative { "!" } else { "" };
507        let generics = if self.generics.is_empty() {
508            String::new()
509        } else {
510            format!("<{}>", self.generics.join(", "))
511        };
512
513        match &self.trait_name {
514            Some(trait_name) => format!(
515                "{}impl{} {}{} for {}",
516                unsafe_str, generics, negative_str, trait_name, self.self_ty
517            ),
518            None => format!("impl{} {}", generics, self.self_ty),
519        }
520    }
521}
522
523/// Information about a module
524#[derive(Debug, Clone)]
525pub struct ModuleInfo {
526    pub name: String,
527    pub path: String,
528    pub visibility: Visibility,
529    pub items: Vec<String>,
530    pub submodules: Vec<String>,
531    pub documentation: Option<String>,
532    pub is_inline: bool,
533    pub source_location: SourceLocation,
534    /// Module path for fully qualified naming
535    pub module_path: Vec<String>,
536}
537
538/// Type alias information
539#[derive(Debug, Clone)]
540pub struct TypeAliasInfo {
541    pub name: String,
542    pub visibility: Visibility,
543    pub generics: Vec<String>,
544    pub ty: String,
545    pub documentation: Option<String>,
546    pub where_clause: Option<String>,
547    pub source_location: SourceLocation,
548    /// Module path for fully qualified naming
549    pub module_path: Vec<String>,
550}
551
552/// Const item information
553#[derive(Debug, Clone)]
554pub struct ConstInfo {
555    pub name: String,
556    pub visibility: Visibility,
557    pub ty: String,
558    pub value: Option<String>,
559    pub documentation: Option<String>,
560    pub source_location: SourceLocation,
561    /// Module path for fully qualified naming
562    pub module_path: Vec<String>,
563}
564
565/// Static item information
566#[derive(Debug, Clone)]
567pub struct StaticInfo {
568    pub name: String,
569    pub visibility: Visibility,
570    pub ty: String,
571    pub is_mut: bool,
572    pub documentation: Option<String>,
573    pub source_location: SourceLocation,
574    /// Module path for fully qualified naming
575    pub module_path: Vec<String>,
576}