1use super::{Tool, Result, ToolError, common_options, parse_output_format, OutputFormat};
2use clap::{Arg, ArgMatches, Command};
3use colored::*;
4use std::fs;
5use std::path::Path;
6use std::collections::HashMap;
7use syn::{
8 parse_file, File, Item, ItemTrait, ItemImpl, TraitItem, visit::Visit,
9 spanned::Spanned,
10};
11use quote::quote;
12use proc_macro2::TokenStream;
13#[derive(Debug, Clone)]
14pub struct TraitExplorerTool;
15#[derive(Debug, Clone)]
16struct TraitDefinition {
17 name: String,
18 methods: Vec<TraitMethod>,
19 supertraits: Vec<String>,
20 visibility: String,
21 attributes: Vec<String>,
22 file_path: String,
23 line_number: usize,
24}
25#[derive(Debug, Clone)]
26struct TraitMethod {
27 name: String,
28 signature: String,
29 is_required: bool,
30 has_default_implementation: bool,
31}
32#[derive(Debug, Clone)]
33struct TraitImplementation {
34 trait_name: String,
35 target_type: String,
36 methods: Vec<ImplMethod>,
37 file_path: String,
38 line_number: usize,
39 is_foreign: bool,
40}
41#[derive(Debug, Clone)]
42struct ImplMethod {
43 name: String,
44 is_override: bool,
45}
46#[derive(Debug, Clone)]
47struct TraitAnalysis {
48 trait_definitions: Vec<TraitDefinition>,
49 trait_implementations: Vec<TraitImplementation>,
50 trait_usage_patterns: HashMap<String, Vec<String>>,
51 orphan_rules_violations: Vec<String>,
52 missing_implementations: Vec<String>,
53}
54#[derive(Debug, Clone)]
55struct TraitGraph {
56 nodes: Vec<String>,
57 edges: Vec<(String, String)>,
58}
59#[derive(Debug, Clone)]
60struct TraitSuggestion {
61 trait_name: String,
62 target_type: String,
63 reason: String,
64 confidence: f64,
65}
66impl TraitExplorerTool {
67 pub fn new() -> Self {
68 Self
69 }
70 fn discover_trait_definitions(
71 &self,
72 source_path: &str,
73 ) -> Result<Vec<TraitDefinition>> {
74 let mut traits = Vec::new();
75 self.analyze_directory_for_traits(source_path, &mut traits)?;
76 Ok(traits)
77 }
78 fn analyze_directory_for_traits(
79 &self,
80 dir_path: &str,
81 traits: &mut Vec<TraitDefinition>,
82 ) -> Result<()> {
83 let entries = fs::read_dir(dir_path)
84 .map_err(|e| ToolError::ExecutionFailed(
85 format!("Failed to read directory {}: {}", dir_path, e),
86 ))?;
87 for entry in entries {
88 let entry = entry?;
89 let path = entry.path();
90 if path.is_dir() {
91 self.analyze_directory_for_traits(&path.to_string_lossy(), traits)?;
92 } else if let Some(ext) = path.extension() {
93 if ext == "rs" {
94 self.analyze_file_for_traits(&path, traits)?;
95 }
96 }
97 }
98 Ok(())
99 }
100 fn analyze_file_for_traits(
101 &self,
102 file_path: &Path,
103 traits: &mut Vec<TraitDefinition>,
104 ) -> Result<()> {
105 let content = fs::read_to_string(file_path)?;
106 let ast = parse_file(&content)?;
107 struct TraitVisitor<'a> {
108 traits: &'a mut Vec<TraitDefinition>,
109 current_file: String,
110 }
111 impl<'a> Visit<'_> for TraitVisitor<'a> {
112 fn visit_item_trait(&mut self, node: &ItemTrait) {
113 let trait_def = TraitDefinition {
114 name: node.ident.to_string(),
115 methods: Self::extract_trait_methods(&node.items),
116 supertraits: Self::extract_supertraits(&node.supertraits),
117 visibility: if matches!(node.vis, syn::Visibility::Public(_)) {
118 "pub".to_string()
119 } else {
120 "private".to_string()
121 },
122 attributes: Self::extract_attributes(&node.attrs),
123 file_path: self.current_file.clone(),
124 line_number: 0,
125 };
126 self.traits.push(trait_def);
127 }
128 }
129 impl TraitVisitor<'_> {
130 fn extract_trait_methods(items: &[TraitItem]) -> Vec<TraitMethod> {
131 let mut methods = Vec::new();
132 for item in items {
133 if let TraitItem::Fn(method) = item {
134 let name = method.sig.ident.to_string();
135 let signature = Self::format_method_signature(&method.sig);
136 let (is_required, has_default) = match &method.default {
137 Some(_) => (false, true),
138 None => (true, false),
139 };
140 methods
141 .push(TraitMethod {
142 name,
143 signature,
144 is_required,
145 has_default_implementation: has_default,
146 });
147 }
148 }
149 methods
150 }
151 fn extract_supertraits(
152 supertraits: &syn::punctuated::Punctuated<
153 syn::TypeParamBound,
154 syn::token::Plus,
155 >,
156 ) -> Vec<String> {
157 let mut traits = Vec::new();
158 for bound in supertraits {
159 if let syn::TypeParamBound::Trait(trait_bound) = bound {
160 let trait_name = trait_bound
161 .path
162 .segments
163 .iter()
164 .map(|seg| seg.ident.to_string())
165 .collect::<Vec<_>>()
166 .join("::");
167 traits.push(trait_name);
168 }
169 }
170 traits
171 }
172 fn extract_attributes(attrs: &[syn::Attribute]) -> Vec<String> {
173 attrs
174 .iter()
175 .map(|attr| {
176 attr.path()
177 .segments
178 .iter()
179 .map(|seg| seg.ident.to_string())
180 .collect::<Vec<_>>()
181 .join("::")
182 })
183 .collect()
184 }
185 fn format_method_signature(sig: &syn::Signature) -> String {
186 let params = sig
187 .inputs
188 .iter()
189 .filter_map(|arg| {
190 match arg {
191 syn::FnArg::Receiver(_) => Some("self".to_string()),
192 syn::FnArg::Typed(pat_type) => {
193 if let syn::Pat::Ident(pat_ident) = &*pat_type.pat {
194 Some(
195 format!(
196 "{}: {}", pat_ident.ident, Self::type_to_string(&* pat_type
197 .ty)
198 ),
199 )
200 } else {
201 None
202 }
203 }
204 }
205 })
206 .collect::<Vec<_>>()
207 .join(", ");
208 let return_type = match &sig.output {
209 syn::ReturnType::Default => String::new(),
210 syn::ReturnType::Type(_, ty) => {
211 format!(" -> {}", Self::type_to_string(ty))
212 }
213 };
214 format!("fn {}({}){}", sig.ident, params, return_type)
215 }
216 fn type_to_string(ty: &syn::Type) -> String {
217 match ty {
218 syn::Type::Path(type_path) => {
219 type_path
220 .path
221 .segments
222 .iter()
223 .map(|seg| seg.ident.to_string())
224 .collect::<Vec<_>>()
225 .join("::")
226 }
227 syn::Type::Reference(type_ref) => {
228 let mut result = "&".to_string();
229 if type_ref.mutability.is_some() {
230 result.push_str("mut ");
231 }
232 result.push_str(&Self::type_to_string(&*type_ref.elem));
233 result
234 }
235 _ => "Unknown".to_string(),
236 }
237 }
238 }
239 let mut visitor = TraitVisitor {
240 traits,
241 current_file: file_path.to_string_lossy().to_string(),
242 };
243 syn::visit::visit_file(&mut visitor, &ast);
244 Ok(())
245 }
246 fn discover_trait_implementations(
247 &self,
248 source_path: &str,
249 ) -> Result<Vec<TraitImplementation>> {
250 let mut implementations = Vec::new();
251 self.analyze_directory_for_implementations(source_path, &mut implementations)?;
252 Ok(implementations)
253 }
254 fn analyze_directory_for_implementations(
255 &self,
256 dir_path: &str,
257 implementations: &mut Vec<TraitImplementation>,
258 ) -> Result<()> {
259 let entries = fs::read_dir(dir_path)
260 .map_err(|e| ToolError::ExecutionFailed(
261 format!("Failed to read directory {}: {}", dir_path, e),
262 ))?;
263 for entry in entries {
264 let entry = entry?;
265 let path = entry.path();
266 if path.is_dir() {
267 self.analyze_directory_for_implementations(
268 &path.to_string_lossy(),
269 implementations,
270 )?;
271 } else if let Some(ext) = path.extension() {
272 if ext == "rs" {
273 self.analyze_file_for_implementations(&path, implementations)?;
274 }
275 }
276 }
277 Ok(())
278 }
279 fn analyze_file_for_implementations(
280 &self,
281 file_path: &Path,
282 implementations: &mut Vec<TraitImplementation>,
283 ) -> Result<()> {
284 let content = fs::read_to_string(file_path)?;
285 let ast = parse_file(&content)?;
286 struct ImplVisitor<'a> {
287 implementations: &'a mut Vec<TraitImplementation>,
288 current_file: String,
289 }
290 impl<'a> Visit<'_> for ImplVisitor<'a> {
291 fn visit_item_impl(&mut self, node: &ItemImpl) {
292 if let Some((_, trait_path, _)) = &node.trait_ {
293 let trait_name = trait_path
294 .segments
295 .iter()
296 .map(|seg| seg.ident.to_string())
297 .collect::<Vec<_>>()
298 .join("::");
299 let target_type = Self::extract_target_type(&node.self_ty);
300 let methods = node
301 .items
302 .iter()
303 .filter_map(|item| {
304 match item {
305 syn::ImplItem::Fn(method) => {
306 Some(ImplMethod {
307 name: method.sig.ident.to_string(),
308 is_override: method
309 .attrs
310 .iter()
311 .any(|attr| {
312 attr.path()
313 .segments
314 .iter()
315 .any(|seg| seg.ident == "override")
316 }),
317 })
318 }
319 _ => None,
320 }
321 })
322 .collect();
323 let impl_info = TraitImplementation {
324 trait_name,
325 target_type,
326 methods,
327 file_path: self.current_file.clone(),
328 line_number: 0,
329 is_foreign: false,
330 };
331 self.implementations.push(impl_info);
332 }
333 }
334 }
335 impl ImplVisitor<'_> {
336 fn extract_target_type(ty: &syn::Type) -> String {
337 match ty {
338 syn::Type::Path(type_path) => {
339 type_path
340 .path
341 .segments
342 .iter()
343 .map(|seg| seg.ident.to_string())
344 .collect::<Vec<_>>()
345 .join("::")
346 }
347 _ => "Unknown".to_string(),
348 }
349 }
350 }
351 let mut visitor = ImplVisitor {
352 implementations,
353 current_file: file_path.to_string_lossy().to_string(),
354 };
355 syn::visit::visit_file(&mut visitor, &ast);
356 Ok(())
357 }
358 fn analyze_trait_usage(
359 &self,
360 implementations: &[TraitImplementation],
361 ) -> Result<HashMap<String, Vec<String>>> {
362 let mut usage_patterns = HashMap::new();
363 for impl_info in implementations {
364 usage_patterns
365 .entry(impl_info.trait_name.clone())
366 .or_insert_with(Vec::new)
367 .push(impl_info.target_type.clone());
368 }
369 Ok(usage_patterns)
370 }
371 fn find_missing_implementations(
372 &self,
373 traits: &[TraitDefinition],
374 implementations: &[TraitImplementation],
375 ) -> Vec<String> {
376 let mut missing = Vec::new();
377 let implemented_traits: HashMap<String, Vec<String>> = implementations
378 .iter()
379 .fold(
380 HashMap::new(),
381 |mut acc, impl_info| {
382 acc.entry(impl_info.trait_name.clone())
383 .or_insert_with(Vec::new)
384 .push(impl_info.target_type.clone());
385 acc
386 },
387 );
388 for trait_def in traits {
389 if let Some(implementors) = implemented_traits.get(&trait_def.name) {
390 if implementors.is_empty() {
391 missing
392 .push(
393 format!("Trait '{}' has no implementations", trait_def.name),
394 );
395 }
396 } else {
397 missing
398 .push(format!("Trait '{}' has no implementations", trait_def.name));
399 }
400 }
401 missing
402 }
403 fn generate_trait_documentation(
404 &self,
405 traits: &[TraitDefinition],
406 implementations: &[TraitImplementation],
407 ) -> Result<String> {
408 let mut docs = String::from("# Trait Implementation Analysis\n\n");
409 docs.push_str(
410 &format!(
411 "Generated on: {}\n\n", chrono::Utc::now().format("%Y-%m-%d %H:%M:%S")
412 ),
413 );
414 docs.push_str("## š Overview\n\n");
415 docs.push_str(&format!("- **Total Traits**: {}\n", traits.len()));
416 docs.push_str(
417 &format!("- **Total Implementations**: {}\n", implementations.len()),
418 );
419 let trait_usage: HashMap<String, usize> = implementations
420 .iter()
421 .fold(
422 HashMap::new(),
423 |mut acc, impl_info| {
424 *acc.entry(impl_info.trait_name.clone()).or_insert(0) += 1;
425 acc
426 },
427 );
428 let most_used_trait = trait_usage
429 .iter()
430 .max_by_key(|(_, count)| *count)
431 .map(|(name, _)| name.as_str())
432 .unwrap_or("None");
433 docs.push_str(&format!("- **Most Implemented Trait**: {}\n\n", most_used_trait));
434 docs.push_str("## šÆ Trait Implementations\n\n");
435 for trait_def in traits {
436 docs.push_str(&format!("### `{}` Trait\n", trait_def.name));
437 docs.push_str(&format!("**File:** `{}`\n", trait_def.file_path));
438 docs.push_str(&format!("**Visibility:** {}\n\n", trait_def.visibility));
439 if !trait_def.supertraits.is_empty() {
440 docs.push_str("**Supertraits:**\n");
441 for supertrait in &trait_def.supertraits {
442 docs.push_str(&format!("- `{}`\n", supertrait));
443 }
444 docs.push_str("\n");
445 }
446 docs.push_str("**Methods:**\n");
447 for method in &trait_def.methods {
448 let required = if method.is_required { "Required" } else { "Optional" };
449 let default = if method.has_default_implementation {
450 " (has default)"
451 } else {
452 ""
453 };
454 docs.push_str(
455 &format!("- `{}` - {}{}\n", method.signature, required, default),
456 );
457 }
458 docs.push_str("\n");
459 let trait_implementations: Vec<&TraitImplementation> = implementations
460 .iter()
461 .filter(|impl_info| impl_info.trait_name == trait_def.name)
462 .collect();
463 if !trait_implementations.is_empty() {
464 docs.push_str("**Known Implementations:**\n");
465 for impl_info in &trait_implementations {
466 docs.push_str(
467 &format!(
468 "- `{}` in `{}`\n", impl_info.target_type, impl_info
469 .file_path
470 ),
471 );
472 }
473 } else {
474 docs.push_str("**No implementations found**\n");
475 }
476 docs.push_str("\n");
477 }
478 let missing = self.find_missing_implementations(traits, implementations);
479 if !missing.is_empty() {
480 docs.push_str("## ā ļø Missing Implementations\n\n");
481 for issue in &missing {
482 docs.push_str(&format!("- {}\n", issue));
483 }
484 docs.push_str("\n");
485 }
486 Ok(docs)
487 }
488 fn generate_trait_visualization(
489 &self,
490 traits: &[TraitDefinition],
491 implementations: &[TraitImplementation],
492 format: &str,
493 ) -> Result<String> {
494 match format {
495 "mermaid" => self.generate_mermaid_graph(traits, implementations),
496 "dot" => self.generate_dot_graph(traits, implementations),
497 _ => {
498 Err(
499 ToolError::InvalidArguments(
500 format!("Unsupported visualization format: {}", format),
501 ),
502 )
503 }
504 }
505 }
506 fn generate_mermaid_graph(
507 &self,
508 traits: &[TraitDefinition],
509 implementations: &[TraitImplementation],
510 ) -> Result<String> {
511 let mut mermaid = String::from("```mermaid\ngraph TD\n");
512 for trait_def in traits {
513 mermaid
514 .push_str(
515 &format!(
516 " T{}[\"Trait: {}\"]\n", trait_def.name.replace("::", "_"),
517 trait_def.name
518 ),
519 );
520 }
521 for impl_info in implementations {
522 let trait_node = impl_info.trait_name.replace("::", "_");
523 let type_node = impl_info.target_type.replace("::", "_");
524 mermaid
525 .push_str(
526 &format!(
527 " T{} --> I{}[\"Impl: {}\"]\n", trait_node, type_node,
528 impl_info.target_type
529 ),
530 );
531 }
532 for trait_def in traits {
533 for supertrait in &trait_def.supertraits {
534 let super_node = supertrait.replace("::", "_");
535 let trait_node = trait_def.name.replace("::", "_");
536 mermaid
537 .push_str(
538 &format!(
539 " T{} --> T{}[\"Supertrait: {}\"]\n", trait_node,
540 super_node, supertrait
541 ),
542 );
543 }
544 }
545 mermaid.push_str("```\n");
546 Ok(mermaid)
547 }
548 fn generate_dot_graph(
549 &self,
550 traits: &[TraitDefinition],
551 implementations: &[TraitImplementation],
552 ) -> Result<String> {
553 let mut dot = String::from("digraph TraitGraph {\n");
554 dot.push_str(" rankdir=LR;\n");
555 dot.push_str(" node [shape=box];\n\n");
556 for trait_def in traits {
557 dot.push_str(
558 &format!(
559 " \"{}\" [label=\"Trait: {}\", fillcolor=lightblue, style=filled];\n",
560 trait_def.name, trait_def.name
561 ),
562 );
563 }
564 for impl_info in implementations {
565 dot.push_str(
566 &format!(
567 " \"{}\" [label=\"Impl: {}\"];\n", impl_info.target_type,
568 impl_info.target_type
569 ),
570 );
571 dot.push_str(
572 &format!(
573 " \"{}\" -> \"{}\" [label=\"implements\"];\n", impl_info
574 .target_type, impl_info.trait_name
575 ),
576 );
577 }
578 for trait_def in traits {
579 for supertrait in &trait_def.supertraits {
580 dot.push_str(
581 &format!(
582 " \"{}\" -> \"{}\" [label=\"extends\", style=dashed];\n",
583 trait_def.name, supertrait
584 ),
585 );
586 }
587 }
588 dot.push_str("}\n");
589 Ok(dot)
590 }
591 fn suggest_trait_implementations(
592 &self,
593 traits: &[TraitDefinition],
594 implementations: &[TraitImplementation],
595 ) -> Vec<TraitSuggestion> {
596 let mut suggestions = Vec::new();
597 let common_types = vec![
598 "String", "i32", "i64", "bool", "Vec<T>", "HashMap<K, V>", "Option<T>",
599 "Result<T, E>"
600 ];
601 for trait_def in traits {
602 let implementation_count = implementations
603 .iter()
604 .filter(|impl_info| impl_info.trait_name == trait_def.name)
605 .count();
606 if implementation_count > 5 {
607 continue;
608 }
609 for common_type in &common_types {
610 let already_implemented = implementations
611 .iter()
612 .any(|impl_info| {
613 impl_info.trait_name == trait_def.name
614 && impl_info.target_type == *common_type
615 });
616 if !already_implemented {
617 let confidence = if common_type.contains("String")
618 && trait_def.name.contains("Display")
619 {
620 0.9
621 } else if common_type.contains("Vec")
622 && trait_def.name.contains("IntoIterator")
623 {
624 0.8
625 } else {
626 0.5
627 };
628 suggestions
629 .push(TraitSuggestion {
630 trait_name: trait_def.name.clone(),
631 target_type: common_type.to_string(),
632 reason: format!(
633 "{} would benefit from {} implementation", common_type,
634 trait_def.name
635 ),
636 confidence,
637 });
638 }
639 }
640 }
641 suggestions
642 .sort_by(|a, b| {
643 b.confidence
644 .partial_cmp(&a.confidence)
645 .unwrap_or(std::cmp::Ordering::Equal)
646 });
647 suggestions
648 }
649 fn generate_implementations_report(
650 &self,
651 _traits: &[TraitDefinition],
652 _implementations: &[TraitImplementation],
653 ) -> Result<String> {
654 Err(
655 ToolError::ExecutionFailed(
656 "Implementation report feature not yet implemented".to_string(),
657 ),
658 )
659 }
660 fn generate_missing_report(&self, _missing: &[String]) -> Result<String> {
661 Err(
662 ToolError::ExecutionFailed(
663 "Missing implementations report feature not yet implemented".to_string(),
664 ),
665 )
666 }
667 fn generate_suggestions_report(
668 &self,
669 _suggestions: &[TraitSuggestion],
670 ) -> Result<String> {
671 Err(
672 ToolError::ExecutionFailed(
673 "Suggestions report feature not yet implemented".to_string(),
674 ),
675 )
676 }
677}
678impl Tool for TraitExplorerTool {
679 fn name(&self) -> &'static str {
680 "trait-explorer"
681 }
682 fn description(&self) -> &'static str {
683 "Explore and analyze trait implementations across the workspace"
684 }
685 fn command(&self) -> Command {
686 Command::new(self.name())
687 .about(self.description())
688 .long_about(
689 "Discover all trait implementations in your codebase, analyze usage patterns, find missing implementations, and generate comprehensive trait documentation.",
690 )
691 .args(
692 &[
693 Arg::new("input")
694 .long("input")
695 .short('i')
696 .help("Input directory to analyze")
697 .default_value("src/"),
698 Arg::new("trait")
699 .long("trait")
700 .short('t')
701 .help("Specific trait to explore"),
702 Arg::new("implementations")
703 .long("implementations")
704 .help("Show all implementations of specified trait")
705 .action(clap::ArgAction::SetTrue),
706 Arg::new("missing")
707 .long("missing")
708 .help("Find missing trait implementations")
709 .action(clap::ArgAction::SetTrue),
710 Arg::new("usage")
711 .long("usage")
712 .help("Analyze trait usage patterns")
713 .action(clap::ArgAction::SetTrue),
714 Arg::new("visualize")
715 .long("visualize")
716 .short('v')
717 .help("Generate trait relationship visualization")
718 .action(clap::ArgAction::SetTrue),
719 Arg::new("format")
720 .long("format")
721 .help("Output format: markdown, json, mermaid, dot")
722 .default_value("markdown"),
723 Arg::new("output")
724 .long("output")
725 .short('o')
726 .help("Output file for analysis")
727 .default_value("trait-analysis.md"),
728 Arg::new("suggest")
729 .long("suggest")
730 .help("Suggest additional trait implementations")
731 .action(clap::ArgAction::SetTrue),
732 Arg::new("workspace")
733 .long("workspace")
734 .help("Analyze all crates in workspace")
735 .action(clap::ArgAction::SetTrue),
736 ],
737 )
738 .args(&common_options())
739 }
740 fn execute(&self, matches: &ArgMatches) -> Result<()> {
741 let input = matches.get_one::<String>("input").unwrap();
742 let specific_trait = matches.get_one::<String>("trait");
743 let implementations_only = matches.get_flag("implementations");
744 let missing_only = matches.get_flag("missing");
745 let usage_analysis = matches.get_flag("usage");
746 let visualize = matches.get_flag("visualize");
747 let format = matches.get_one::<String>("format").unwrap();
748 let output = matches.get_one::<String>("output").unwrap();
749 let suggest = matches.get_flag("suggest");
750 let workspace = matches.get_flag("workspace");
751 let dry_run = matches.get_flag("dry-run");
752 let verbose = matches.get_flag("verbose");
753 let output_format = parse_output_format(matches);
754 println!(
755 "š {} - {}", "CargoMate TraitExplorer".bold().blue(), self.description()
756 .cyan()
757 );
758 if !Path::new(input).exists() {
759 return Err(
760 ToolError::InvalidArguments(format!("Input path not found: {}", input)),
761 );
762 }
763 if verbose {
764 println!(" š Analyzing trait ecosystem in {}", input);
765 }
766 let trait_definitions = self.discover_trait_definitions(input)?;
767 if verbose {
768 println!(" š Found {} trait definitions", trait_definitions.len());
769 }
770 let trait_implementations = self.discover_trait_implementations(input)?;
771 if verbose {
772 println!(
773 " š Found {} trait implementations", trait_implementations.len()
774 );
775 }
776 let (filtered_definitions, filtered_implementations) = if let Some(trait_name) = specific_trait {
777 let defs: Vec<TraitDefinition> = trait_definitions
778 .into_iter()
779 .filter(|t| t.name == *trait_name)
780 .collect();
781 let impls: Vec<TraitImplementation> = trait_implementations
782 .into_iter()
783 .filter(|i| i.trait_name == *trait_name)
784 .collect();
785 (defs, impls)
786 } else {
787 (trait_definitions, trait_implementations)
788 };
789 if filtered_definitions.is_empty() {
790 println!("{}", "No traits found matching criteria.".yellow());
791 return Ok(());
792 }
793 let usage_patterns = self.analyze_trait_usage(&filtered_implementations)?;
794 let missing_implementations = self
795 .find_missing_implementations(
796 &filtered_definitions,
797 &filtered_implementations,
798 );
799 let suggestions = if suggest {
800 self.suggest_trait_implementations(
801 &filtered_definitions,
802 &filtered_implementations,
803 )
804 } else {
805 Vec::new()
806 };
807 let mut output_content = String::new();
808 if implementations_only {
809 output_content = self
810 .generate_implementations_report(
811 &filtered_definitions,
812 &filtered_implementations,
813 )?;
814 } else if missing_only {
815 output_content = self.generate_missing_report(&missing_implementations)?;
816 } else if visualize {
817 output_content = self
818 .generate_trait_visualization(
819 &filtered_definitions,
820 &filtered_implementations,
821 format,
822 )?;
823 } else if suggest {
824 output_content = self.generate_suggestions_report(&suggestions)?;
825 } else {
826 output_content = self
827 .generate_trait_documentation(
828 &filtered_definitions,
829 &filtered_implementations,
830 )?;
831 }
832 match output_format {
833 OutputFormat::Human => {
834 println!(" ā
Generated trait analysis");
835 println!(" ā {}", output.cyan());
836 if implementations_only {
837 println!(
838 " š Showing implementations for {} traits",
839 filtered_definitions.len()
840 );
841 } else if missing_only {
842 println!(
843 " ā ļø Found {} potential missing implementations",
844 missing_implementations.len()
845 );
846 } else if visualize {
847 println!(" š Generated {} visualization", format);
848 } else if suggest {
849 println!(
850 " š” Generated {} implementation suggestions", suggestions
851 .len()
852 );
853 }
854 if dry_run {
855 println!(" š {}", "Analysis preview:".bold());
856 println!(" {}", "ā".repeat(50));
857 for line in output_content.lines().take(15) {
858 println!(" {}", line);
859 }
860 if output_content.lines().count() > 15 {
861 println!(" ... (truncated)");
862 }
863 } else {
864 if let Some(parent) = Path::new(output).parent() {
865 fs::create_dir_all(parent)
866 .map_err(|e| ToolError::ExecutionFailed(
867 format!("Failed to create output directory: {}", e),
868 ))?;
869 }
870 fs::write(output, &output_content)
871 .map_err(|e| ToolError::ExecutionFailed(
872 format!("Failed to write {}: {}", output, e),
873 ))?;
874 println!(" š¾ Analysis written successfully");
875 }
876 }
877 OutputFormat::Json => {
878 let result = serde_json::json!(
879 { "traits_analyzed" : filtered_definitions.len(),
880 "implementations_found" : filtered_implementations.len(),
881 "missing_implementations" : missing_implementations.len(),
882 "suggestions_count" : suggestions.len(), "analysis_content" :
883 output_content }
884 );
885 println!("{}", serde_json::to_string_pretty(& result).unwrap());
886 }
887 OutputFormat::Table => {
888 println!(
889 "{:<25} {:<15} {:<12} {:<10} {:<12}", "Analysis Type", "Traits",
890 "Impls", "Missing", "Suggestions"
891 );
892 println!("{}", "ā".repeat(80));
893 println!(
894 "{:<25} {:<15} {:<12} {:<10} {:<12}", if implementations_only {
895 "Implementations" } else if missing_only { "Missing" } else if
896 visualize { "Visualization" } else if suggest { "Suggestions" } else
897 { "Full Analysis" }, filtered_definitions.len(),
898 filtered_implementations.len(), missing_implementations.len(),
899 suggestions.len()
900 );
901 }
902 }
903 println!("\nš Trait exploration completed!");
904 Ok(())
905 }
906}
907impl Default for TraitExplorerTool {
908 fn default() -> Self {
909 Self::new()
910 }
911}