1use crate::core::{FileMetrics, FunctionMetrics};
2use std::sync::Arc;
3
4pub mod guidance;
5pub mod opportunities;
6pub mod patterns;
7
8pub use guidance::*;
9pub use opportunities::*;
10pub use patterns::*;
11
12#[derive(Debug, Clone)]
13pub struct RefactoringAnalysis {
14 pub function_name: String,
15 pub function_role: FunctionRole,
16 pub detected_patterns: Vec<DetectedPattern>,
17 pub refactoring_opportunities: Vec<RefactoringOpportunity>,
18 pub quality_assessment: QualityAssessment,
19 pub recommendations: Vec<Recommendation>,
20}
21
22#[derive(Debug, Clone)]
23pub enum FunctionRole {
24 PureLogic {
25 complexity_tolerance: u32,
26 testing_expectation: TestingExpectation,
27 },
28 IOOrchestrator {
29 expected_patterns: Vec<OrchestrationPattern>,
30 complexity_tolerance: u32,
31 },
32 FormattingFunction {
33 input_types: Vec<String>,
34 output_type: String,
35 testability_importance: TestabilityImportance,
36 },
37 TraitImplementation {
38 trait_name: String,
39 testing_strategy: TraitTestingStrategy,
40 },
41 FrameworkCallback {
42 framework: String,
43 callback_type: CallbackType,
44 },
45}
46
47#[derive(Debug, Clone)]
48pub enum TestingExpectation {
49 HighCoverage,
50 ModerateCoverage,
51 LowCoverage,
52}
53
54#[derive(Debug, Clone)]
55pub enum TestabilityImportance {
56 Critical,
57 High,
58 Medium,
59 Low,
60}
61
62#[derive(Debug, Clone)]
63pub enum TraitTestingStrategy {
64 TestThroughCallers,
65 DirectUnitTests,
66 IntegrationTests,
67}
68
69#[derive(Debug, Clone)]
70pub enum CallbackType {
71 EventHandler,
72 Lifecycle,
73 DataTransform,
74}
75
76#[derive(Debug, Clone)]
77pub struct OrchestrationPattern {
78 pub pattern_type: String,
79 pub description: String,
80}
81
82#[derive(Debug, Clone)]
83pub struct DetectedPattern {
84 pub pattern_type: PatternType,
85 pub confidence: f64,
86 pub evidence: PatternEvidence,
87 pub assessment: PatternAssessment,
88}
89
90#[derive(Debug, Clone)]
91pub enum PatternType {
92 IOOrchestration(OrchestrationPattern),
93 PureFormatting(FormattingPattern),
94 MixedConcerns(ConcernMixingPattern),
95 TraitImplementation(TraitPattern),
96 TestFunction(TestPattern),
97 FunctionalComposition,
98 ImperativeLoop,
99 MutableState,
100 SideEffects,
101}
102
103#[derive(Debug, Clone)]
104pub struct FormattingPattern {
105 pub format_type: String,
106 pub complexity: u32,
107}
108
109#[derive(Debug, Clone)]
110pub struct ConcernMixingPattern {
111 pub concerns: Vec<String>,
112 pub separation_difficulty: SeparationDifficulty,
113}
114
115#[derive(Debug, Clone)]
116pub enum SeparationDifficulty {
117 Trivial,
118 Low,
119 Medium,
120 High,
121 VeryHigh,
122}
123
124#[derive(Debug, Clone)]
125pub struct TraitPattern {
126 pub trait_name: String,
127 pub method_name: String,
128}
129
130#[derive(Debug, Clone)]
131pub struct TestPattern {
132 pub test_type: String,
133 pub framework: String,
134}
135
136#[derive(Debug, Clone)]
137pub struct PatternEvidence {
138 pub code_snippets: Vec<String>,
139 pub line_numbers: Vec<u32>,
140 pub confidence_factors: Vec<String>,
141}
142
143#[derive(Debug, Clone)]
144pub enum PatternAssessment {
145 GoodExample {
146 strengths: Vec<String>,
147 why_good: String,
148 },
149 ImprovementOpportunity {
150 current_issues: Vec<String>,
151 potential_benefits: Vec<String>,
152 refactoring_suggestions: Vec<RefactoringOpportunity>,
153 },
154 AntiPattern {
155 problems: Vec<String>,
156 recommended_patterns: Vec<PatternType>,
157 urgency: Urgency,
158 },
159}
160
161#[derive(Debug, Clone)]
162pub enum Urgency {
163 Low,
164 Medium,
165 High,
166 Critical,
167}
168
169#[derive(Debug, Clone)]
170pub struct QualityAssessment {
171 pub overall_score: f64,
172 pub strengths: Vec<String>,
173 pub improvement_areas: Vec<String>,
174 pub pattern_compliance: f64,
175 pub role_appropriateness: f64,
176}
177
178#[derive(Debug, Clone)]
179pub struct Recommendation {
180 pub title: String,
181 pub description: String,
182 pub priority: Priority,
183 pub effort_estimate: EffortEstimate,
184 pub benefits: Vec<String>,
185 pub example: Option<RefactoringExample>,
186}
187
188#[derive(Debug, Clone)]
189pub enum Priority {
190 Low,
191 Medium,
192 High,
193 Critical,
194}
195
196#[derive(Debug, Clone)]
197pub struct RefactoringExample {
198 pub before: String,
199 pub after: String,
200 pub explanation: String,
201}
202
203#[derive(Debug, Clone)]
204pub enum EffortEstimate {
205 Trivial, Low, Medium, High, Significant, }
211
212pub struct PatternRecognitionEngine {
213 pattern_matchers: Vec<Arc<dyn PatternMatcher>>,
214 function_classifier: FunctionRoleClassifier,
215 refactoring_advisor: RefactoringAdvisor,
216}
217
218impl Default for PatternRecognitionEngine {
219 fn default() -> Self {
220 Self {
221 pattern_matchers: patterns::create_pattern_matchers(),
222 function_classifier: FunctionRoleClassifier::default(),
223 refactoring_advisor: RefactoringAdvisor::default(),
224 }
225 }
226}
227
228impl PatternRecognitionEngine {
229 pub fn new() -> Self {
230 Self::default()
231 }
232
233 pub fn analyze_function(
234 &self,
235 function: &FunctionMetrics,
236 file: &FileMetrics,
237 ) -> RefactoringAnalysis {
238 let role = self.function_classifier.classify(function, file);
239 let patterns = self.identify_patterns(function, file);
240 let opportunities = self
241 .refactoring_advisor
242 .find_opportunities(function, file, &role, &patterns);
243 let quality = self.assess_quality(function, &patterns, &role);
244 let recommendations = self.generate_recommendations(&opportunities, &quality);
245
246 RefactoringAnalysis {
247 function_name: function.name.clone(),
248 function_role: role,
249 detected_patterns: patterns,
250 refactoring_opportunities: opportunities,
251 quality_assessment: quality,
252 recommendations,
253 }
254 }
255
256 fn identify_patterns(
257 &self,
258 function: &FunctionMetrics,
259 file: &FileMetrics,
260 ) -> Vec<DetectedPattern> {
261 self.pattern_matchers
262 .iter()
263 .filter_map(|matcher| matcher.match_pattern(function, file))
264 .collect()
265 }
266
267 fn assess_quality(
268 &self,
269 function: &FunctionMetrics,
270 patterns: &[DetectedPattern],
271 role: &FunctionRole,
272 ) -> QualityAssessment {
273 let mut strengths = Vec::new();
274 let mut improvement_areas = Vec::new();
275 let mut pattern_score = 0.0;
276 let mut pattern_count = 0.0;
277
278 for pattern in patterns {
279 pattern_count += 1.0;
280 match &pattern.assessment {
281 PatternAssessment::GoodExample { strengths: s, .. } => {
282 strengths.extend(s.clone());
283 pattern_score += 1.0;
284 }
285 PatternAssessment::ImprovementOpportunity { current_issues, .. } => {
286 improvement_areas.extend(current_issues.clone());
287 pattern_score += 0.5;
288 }
289 PatternAssessment::AntiPattern { problems, .. } => {
290 improvement_areas.extend(problems.clone());
291 }
292 }
293 }
294
295 let pattern_compliance = if pattern_count > 0.0 {
296 pattern_score / pattern_count
297 } else {
298 1.0
299 };
300
301 let role_appropriateness = self.calculate_role_appropriateness(function, role);
302 let overall_score = (pattern_compliance + role_appropriateness) / 2.0;
303
304 QualityAssessment {
305 overall_score,
306 strengths,
307 improvement_areas,
308 pattern_compliance,
309 role_appropriateness,
310 }
311 }
312
313 fn calculate_role_appropriateness(
314 &self,
315 function: &FunctionMetrics,
316 role: &FunctionRole,
317 ) -> f64 {
318 match role {
319 FunctionRole::PureLogic {
320 complexity_tolerance,
321 ..
322 } => {
323 if function.cyclomatic <= *complexity_tolerance {
324 1.0
325 } else {
326 0.5
327 }
328 }
329 FunctionRole::IOOrchestrator {
330 complexity_tolerance,
331 ..
332 } => {
333 if function.cyclomatic <= *complexity_tolerance {
334 1.0
335 } else {
336 0.7
337 }
338 }
339 _ => 0.8,
340 }
341 }
342
343 fn format_patterns<T: std::fmt::Debug>(patterns: &[T]) -> String {
345 patterns
346 .iter()
347 .map(|p| format!("{:?}", p))
348 .collect::<Vec<_>>()
349 .join(", ")
350 }
351
352 fn complexity_to_priority(complexity: &ComplexityLevel) -> Priority {
354 match complexity {
355 ComplexityLevel::Severe => Priority::Critical,
356 ComplexityLevel::High => Priority::High,
357 ComplexityLevel::Moderate => Priority::Medium,
358 _ => Priority::Low,
359 }
360 }
361
362 fn generate_recommendations(
363 &self,
364 opportunities: &[RefactoringOpportunity],
365 _quality: &QualityAssessment,
366 ) -> Vec<Recommendation> {
367 let mut recommendations = Vec::new();
368
369 for opportunity in opportunities {
370 let recommendation = match opportunity {
371 RefactoringOpportunity::ExtractPureFunctions {
372 source_function,
373 complexity_level,
374 extraction_strategy: _,
375 suggested_functions,
376 functional_patterns,
377 benefits,
378 effort_estimate,
379 example,
380 } => {
381 let description = match complexity_level {
382 ComplexityLevel::Moderate => {
383 format!(
384 "Extract {} pure functions using direct functional transformation. \
385 Apply patterns: {}",
386 suggested_functions.len(),
387 Self::format_patterns(functional_patterns)
388 )
389 }
390 ComplexityLevel::High => {
391 format!(
392 "Extract {} pure functions using decompose-then-transform strategy. \
393 First decompose into logical units, then apply functional patterns.",
394 suggested_functions.len()
395 )
396 }
397 ComplexityLevel::Severe => {
398 format!(
399 "Architectural refactoring needed. Extract {} pure functions into modules \
400 and design functional core with imperative shell.",
401 suggested_functions.len()
402 )
403 }
404 _ => continue,
405 };
406
407 Recommendation {
408 title: format!("Extract pure functions from {}", source_function),
409 description,
410 priority: Self::complexity_to_priority(complexity_level),
411 effort_estimate: effort_estimate.clone(),
412 benefits: benefits.clone(),
413 example: example.as_ref().map(|e| RefactoringExample {
414 before: e.before_imperative.clone(),
415 after: e.after_functional.clone(),
416 explanation: Self::format_patterns(&e.patterns_applied),
417 }),
418 }
419 }
420 RefactoringOpportunity::ConvertToFunctionalStyle {
421 imperative_function,
422 target_patterns,
423 benefits,
424 effort_estimate,
425 ..
426 } => Recommendation {
427 title: format!("Convert {} to functional style", imperative_function),
428 description: format!(
429 "Apply functional patterns: {}",
430 Self::format_patterns(target_patterns)
431 ),
432 priority: Priority::Medium,
433 effort_estimate: effort_estimate.clone(),
434 benefits: benefits.clone(),
435 example: None,
436 },
437 RefactoringOpportunity::ExtractSideEffects {
438 mixed_function,
439 pure_core,
440 benefits,
441 effort_estimate,
442 ..
443 } => Recommendation {
444 title: format!("Extract side effects from {}", mixed_function),
445 description: format!(
446 "Create pure function '{}' and move I/O to boundaries",
447 pure_core.name
448 ),
449 priority: Priority::High,
450 effort_estimate: effort_estimate.clone(),
451 benefits: benefits.clone(),
452 example: None,
453 },
454 };
455 recommendations.push(recommendation);
456 }
457
458 recommendations
459 }
460}
461
462pub struct FunctionRoleClassifier {
463 io_detectors: Vec<Arc<dyn IoDetector>>,
464 formatting_detectors: Vec<Arc<dyn FormattingDetector>>,
465 trait_analyzers: Vec<Arc<dyn TraitAnalyzer>>,
466}
467
468impl Default for FunctionRoleClassifier {
469 fn default() -> Self {
470 Self {
471 io_detectors: patterns::create_io_detectors(),
472 formatting_detectors: patterns::create_formatting_detectors(),
473 trait_analyzers: patterns::create_trait_analyzers(),
474 }
475 }
476}
477
478impl FunctionRoleClassifier {
479 pub fn new() -> Self {
480 Self::default()
481 }
482
483 pub fn classify(&self, function: &FunctionMetrics, file: &FileMetrics) -> FunctionRole {
484 for analyzer in &self.trait_analyzers {
486 if let Some(trait_info) = analyzer.detect_trait_implementation(function, file) {
487 return FunctionRole::TraitImplementation {
488 trait_name: trait_info.trait_name,
489 testing_strategy: TraitTestingStrategy::TestThroughCallers,
490 };
491 }
492 }
493
494 for detector in &self.io_detectors {
496 if let Some(io_info) = detector.detect_io_orchestration(function, file) {
497 return FunctionRole::IOOrchestrator {
498 expected_patterns: io_info.patterns,
499 complexity_tolerance: 5,
500 };
501 }
502 }
503
504 for detector in &self.formatting_detectors {
506 if let Some(formatting_info) = detector.detect_formatting_function(function, file) {
507 return FunctionRole::FormattingFunction {
508 input_types: formatting_info.inputs,
509 output_type: formatting_info.output,
510 testability_importance: TestabilityImportance::High,
511 };
512 }
513 }
514
515 FunctionRole::PureLogic {
517 complexity_tolerance: 3,
518 testing_expectation: TestingExpectation::HighCoverage,
519 }
520 }
521}
522
523pub struct RefactoringAdvisor {
524 opportunity_detectors: Vec<Arc<dyn RefactoringDetector>>,
525}
526
527impl Default for RefactoringAdvisor {
528 fn default() -> Self {
529 Self {
530 opportunity_detectors: opportunities::create_refactoring_detectors(),
531 }
532 }
533}
534
535impl RefactoringAdvisor {
536 pub fn new() -> Self {
537 Self::default()
538 }
539
540 pub fn find_opportunities(
541 &self,
542 function: &FunctionMetrics,
543 file: &FileMetrics,
544 role: &FunctionRole,
545 patterns: &[DetectedPattern],
546 ) -> Vec<RefactoringOpportunity> {
547 let mut opportunities = Vec::new();
548
549 for detector in &self.opportunity_detectors {
550 opportunities.extend(detector.detect_opportunities(function, file, role, patterns));
551 }
552
553 opportunities.sort_by_key(|o| match o {
555 RefactoringOpportunity::ExtractPureFunctions {
556 complexity_level, ..
557 } => match complexity_level {
558 ComplexityLevel::Severe => 0,
559 ComplexityLevel::High => 1,
560 ComplexityLevel::Moderate => 2,
561 ComplexityLevel::Low => 3,
562 },
563 RefactoringOpportunity::ExtractSideEffects { .. } => 1,
564 RefactoringOpportunity::ConvertToFunctionalStyle { .. } => 2,
565 });
566
567 opportunities
568 }
569}
570
571pub trait PatternMatcher: Send + Sync {
573 fn match_pattern(
574 &self,
575 function: &FunctionMetrics,
576 file: &FileMetrics,
577 ) -> Option<DetectedPattern>;
578}
579
580pub trait IoDetector: Send + Sync {
581 fn detect_io_orchestration(
582 &self,
583 function: &FunctionMetrics,
584 file: &FileMetrics,
585 ) -> Option<IoInfo>;
586}
587
588pub trait FormattingDetector: Send + Sync {
589 fn detect_formatting_function(
590 &self,
591 function: &FunctionMetrics,
592 file: &FileMetrics,
593 ) -> Option<FormattingInfo>;
594}
595
596pub trait TraitAnalyzer: Send + Sync {
597 fn detect_trait_implementation(
598 &self,
599 function: &FunctionMetrics,
600 file: &FileMetrics,
601 ) -> Option<TraitInfo>;
602}
603
604pub trait RefactoringDetector: Send + Sync {
605 fn detect_opportunities(
606 &self,
607 function: &FunctionMetrics,
608 file: &FileMetrics,
609 role: &FunctionRole,
610 patterns: &[DetectedPattern],
611 ) -> Vec<RefactoringOpportunity>;
612 fn priority(&self) -> Priority;
613}
614
615#[derive(Debug, Clone)]
616pub struct IoInfo {
617 pub patterns: Vec<OrchestrationPattern>,
618 pub io_operations: Vec<String>,
619}
620
621#[derive(Debug, Clone)]
622pub struct FormattingInfo {
623 pub inputs: Vec<String>,
624 pub output: String,
625 pub format_type: String,
626}
627
628#[derive(Debug, Clone)]
629pub struct TraitInfo {
630 pub trait_name: String,
631 pub method_name: String,
632}
633
634#[derive(Debug, Clone)]
635pub enum RefactoringOpportunity {
636 ExtractPureFunctions {
637 source_function: String,
638 complexity_level: ComplexityLevel,
639 extraction_strategy: ExtractionStrategy,
640 suggested_functions: Vec<PureFunctionSpec>,
641 functional_patterns: Vec<FunctionalPattern>,
642 benefits: Vec<String>,
643 effort_estimate: EffortEstimate,
644 example: Option<FunctionalTransformExample>,
645 },
646 ConvertToFunctionalStyle {
647 imperative_function: String,
648 current_patterns: Vec<ImperativePattern>,
649 target_patterns: Vec<FunctionalPattern>,
650 transformation_steps: Vec<TransformationStep>,
651 benefits: Vec<String>,
652 effort_estimate: EffortEstimate,
653 },
654 ExtractSideEffects {
655 mixed_function: String,
656 pure_core: PureFunctionSpec,
657 io_shell: IoShellSpec,
658 benefits: Vec<String>,
659 effort_estimate: EffortEstimate,
660 },
661}
662
663#[derive(Debug, Clone, PartialEq)]
664pub enum ComplexityLevel {
665 Low, Moderate, High, Severe, }
670
671#[derive(Debug, Clone)]
672pub enum ExtractionStrategy {
673 DirectFunctionalTransformation {
674 patterns_to_apply: Vec<FunctionalPattern>,
675 functions_to_extract: u32,
676 },
677 DecomposeAndTransform {
678 decomposition_steps: Vec<String>,
679 functions_to_extract: u32,
680 then_apply_patterns: Vec<FunctionalPattern>,
681 },
682 ArchitecturalRefactoring {
683 extract_modules: Vec<String>,
684 pure_core_functions: Vec<PureFunctionSpec>,
685 design_imperative_shell: IoShellSpec,
686 },
687}
688
689#[derive(Debug, Clone)]
690pub struct PureFunctionSpec {
691 pub name: String,
692 pub inputs: Vec<String>,
693 pub output: String,
694 pub purpose: String,
695 pub no_side_effects: bool,
696 pub testability: TestabilityLevel,
697}
698
699#[derive(Debug, Clone)]
700pub enum TestabilityLevel {
701 Trivial,
702 Easy,
703 Moderate,
704 Hard,
705}
706
707#[derive(Debug, Clone)]
708pub struct IoShellSpec {
709 pub name: String,
710 pub io_operations: Vec<String>,
711 pub delegates_to: Vec<String>,
712}
713
714#[derive(Debug, Clone)]
715pub enum FunctionalPattern {
716 MapOverLoop,
717 FilterPredicate,
718 FoldAccumulation,
719 PatternMatchOverIfElse,
720 ComposeFunctions,
721 PartialApplication,
722 Monadic(MonadicPattern),
723 Pipeline,
724 Recursion,
725}
726
727#[derive(Debug, Clone)]
728pub enum MonadicPattern {
729 Option,
730 Result,
731 Future,
732 State,
733}
734
735#[derive(Debug, Clone)]
736pub enum ImperativePattern {
737 MutableLoop,
738 StateModification,
739 NestedConditions,
740 SideEffectMixing,
741}
742
743#[derive(Debug, Clone)]
744pub struct TransformationStep {
745 pub description: String,
746 pub pattern_applied: FunctionalPattern,
747}
748
749#[derive(Debug, Clone)]
750pub struct FunctionalTransformExample {
751 pub before_imperative: String,
752 pub after_functional: String,
753 pub patterns_applied: Vec<FunctionalPattern>,
754 pub benefits_demonstrated: Vec<String>,
755}