1#![allow(dead_code)]
9#![allow(unused_variables)]
10#![allow(clippy::upper_case_acronyms)]
11#![allow(clippy::enum_variant_names)]
12#![allow(clippy::vec_init_then_push)]
13#![allow(clippy::regex_creation_in_loops)]
14#![allow(clippy::manual_clamp)]
15
16use anyhow::Result;
17use regex::Regex;
18use std::collections::HashMap;
19
20#[derive(Debug, Clone)]
22pub struct OOPAnalysisInfo {
23 pub class_hierarchies: Vec<ClassHierarchyInfo>,
24 pub design_patterns: Vec<DesignPatternInfo>,
25 pub encapsulation_analysis: Vec<EncapsulationInfo>,
26 pub polymorphism_usage: Vec<PolymorphismInfo>,
27 pub inheritance_patterns: Vec<InheritancePatternInfo>,
28 pub interface_usage: Vec<InterfaceUsageInfo>,
29 pub solid_principles_score: SOLIDPrinciplesScore,
30}
31
32#[derive(Debug, Clone)]
34pub struct ClassHierarchyInfo {
35 pub class_name: String,
36 pub superclass: Option<String>,
37 pub interfaces: Vec<String>,
38 pub subclasses: Vec<String>,
39 pub hierarchy_depth: usize,
40 pub is_abstract: bool,
41 pub is_final: bool,
42 pub modifiers: Vec<String>,
43}
44
45#[derive(Debug, Clone)]
47pub struct DesignPatternInfo {
48 pub pattern_type: DesignPatternType,
49 pub confidence: f32,
50 pub implementation_quality: ImplementationQuality,
51 pub location: String,
52 pub description: String,
53 pub participants: Vec<String>,
54}
55
56#[derive(Debug, Clone)]
58pub enum DesignPatternType {
59 Singleton,
61 Factory,
62 AbstractFactory,
63 Builder,
64 Prototype,
65 Adapter,
67 Bridge,
68 Composite,
69 Decorator,
70 Facade,
71 Flyweight,
72 Proxy,
73 Observer,
75 Strategy,
76 Command,
77 Template,
78 Visitor,
79 Iterator,
80 State,
81 ChainOfResponsibility,
82 Mediator,
83 Memento,
84 Interpreter,
85}
86
87#[derive(Debug, Clone)]
89pub enum ImplementationQuality {
90 Excellent,
91 Good,
92 Adequate,
93 Poor,
94 Incomplete,
95}
96
97#[derive(Debug, Clone)]
99pub struct EncapsulationInfo {
100 pub class_name: String,
101 pub field_access_analysis: Vec<FieldAccessInfo>,
102 pub getter_setter_patterns: Vec<GetterSetterInfo>,
103 pub data_hiding_score: i32,
104 pub immutability_patterns: Vec<ImmutabilityPattern>,
105}
106
107#[derive(Debug, Clone)]
109pub struct FieldAccessInfo {
110 pub field_name: String,
111 pub access_modifier: AccessModifier,
112 pub is_final: bool,
113 pub is_static: bool,
114 pub field_type: String,
115 pub proper_encapsulation: bool,
116}
117
118#[derive(Debug, Clone)]
120pub enum AccessModifier {
121 Public,
122 Protected,
123 Private,
124 PackagePrivate,
125}
126
127#[derive(Debug, Clone)]
129pub struct GetterSetterInfo {
130 pub field_name: String,
131 pub has_getter: bool,
132 pub has_setter: bool,
133 pub getter_name: String,
134 pub setter_name: String,
135 pub follows_naming_convention: bool,
136 pub validation_in_setter: bool,
137}
138
139#[derive(Debug, Clone)]
141pub struct ImmutabilityPattern {
142 pub class_name: String,
143 pub immutability_level: ImmutabilityLevel,
144 pub immutable_fields: Vec<String>,
145 pub builder_pattern_used: bool,
146}
147
148#[derive(Debug, Clone)]
150pub enum ImmutabilityLevel {
151 FullyImmutable,
152 MostlyImmutable,
153 PartiallyImmutable,
154 Mutable,
155}
156
157#[derive(Debug, Clone)]
159pub struct PolymorphismInfo {
160 pub polymorphism_type: PolymorphismType,
161 pub base_type: String,
162 pub derived_types: Vec<String>,
163 pub method_overrides: Vec<MethodOverrideInfo>,
164 pub dynamic_dispatch_usage: bool,
165}
166
167#[derive(Debug, Clone)]
169pub enum PolymorphismType {
170 Inheritance,
171 InterfaceBased,
172 Parametric, AdHoc, }
175
176#[derive(Debug, Clone)]
178pub struct MethodOverrideInfo {
179 pub method_name: String,
180 pub overriding_class: String,
181 pub base_class: String,
182 pub has_override_annotation: bool,
183 pub preserves_contract: bool,
184 pub changes_behavior: bool,
185}
186
187#[derive(Debug, Clone)]
189pub struct InheritancePatternInfo {
190 pub pattern_type: InheritancePatternType,
191 pub base_class: String,
192 pub derived_classes: Vec<String>,
193 pub depth: usize,
194 pub complexity_score: i32,
195 pub potential_issues: Vec<String>,
196}
197
198#[derive(Debug, Clone)]
200pub enum InheritancePatternType {
201 SingleInheritance,
202 InterfaceInheritance,
203 MultipleInterfaceInheritance,
204 DeepInheritance,
205 DiamondProblem, }
207
208#[derive(Debug, Clone)]
210pub struct InterfaceUsageInfo {
211 pub interface_name: String,
212 pub implementing_classes: Vec<String>,
213 pub methods: Vec<InterfaceMethodInfo>,
214 pub functional_interface: bool,
215 pub lambda_usage: Vec<LambdaUsageInfo>,
216}
217
218#[derive(Debug, Clone)]
220pub struct InterfaceMethodInfo {
221 pub method_name: String,
222 pub is_default: bool,
223 pub is_static: bool,
224 pub parameters: Vec<String>,
225 pub return_type: String,
226}
227
228#[derive(Debug, Clone)]
230pub struct LambdaUsageInfo {
231 pub usage_context: String,
232 pub lambda_type: LambdaType,
233 pub complexity: LambdaComplexity,
234 pub captures_variables: bool,
235}
236
237#[derive(Debug, Clone)]
239pub enum LambdaType {
240 Expression,
241 Statement,
242 MethodReference,
243}
244
245#[derive(Debug, Clone)]
247pub enum LambdaComplexity {
248 Simple,
249 Moderate,
250 Complex,
251}
252
253#[derive(Debug, Clone)]
255pub struct SOLIDPrinciplesScore {
256 pub single_responsibility: i32,
257 pub open_closed: i32,
258 pub liskov_substitution: i32,
259 pub interface_segregation: i32,
260 pub dependency_inversion: i32,
261 pub overall_score: i32,
262 pub violations: Vec<SOLIDViolation>,
263}
264
265#[derive(Debug, Clone)]
267pub struct SOLIDViolation {
268 pub principle: SOLIDPrinciple,
269 pub class_name: String,
270 pub description: String,
271 pub severity: ViolationSeverity,
272 pub recommendation: String,
273}
274
275#[derive(Debug, Clone)]
277pub enum SOLIDPrinciple {
278 SingleResponsibility,
279 OpenClosed,
280 LiskovSubstitution,
281 InterfaceSegregation,
282 DependencyInversion,
283}
284
285#[derive(Debug, Clone)]
287pub enum ViolationSeverity {
288 Critical,
289 High,
290 Medium,
291 Low,
292}
293
294#[derive(Debug, Clone)]
296pub struct JavaComprehensiveAnalysis {
297 pub oop_analysis: OOPAnalysisInfo,
298 pub framework_analysis: JavaFrameworkAnalysis,
299 pub security_analysis: JavaSecurityAnalysis,
300 pub modern_features: ModernJavaFeatureAnalysis,
301 pub performance_analysis: JavaPerformanceAnalysis,
302 pub overall_score: i32,
303}
304
305#[derive(Debug, Clone)]
307pub struct JavaAnalysisResult {
308 pub oop_patterns: Vec<String>,
309 pub design_patterns: Vec<String>,
310 pub framework_usage: Vec<String>,
311 pub security_issues: Vec<String>,
312 pub performance_notes: Vec<String>,
313 pub modern_features: Vec<String>,
314 pub complexity_score: i32,
315 pub maintainability_score: i32,
316 pub overall_quality: f32,
317}
318
319#[derive(Debug, Clone)]
321pub struct JavaPerformanceAnalysis {
322 pub algorithm_complexity: Vec<ComplexityAnalysis>,
323 pub collection_usage: Vec<CollectionUsageInfo>,
324 pub memory_patterns: Vec<MemoryPatternInfo>,
325 pub concurrency_patterns: Vec<ConcurrencyPatternInfo>,
326 pub performance_issues: Vec<PerformanceIssue>,
327 pub optimization_opportunities: Vec<OptimizationOpportunity>,
328 pub overall_performance_score: i32,
329}
330
331#[derive(Debug, Clone)]
333pub struct ComplexityAnalysis {
334 pub method_name: String,
335 pub time_complexity: String,
336 pub space_complexity: String,
337 pub complexity_score: i32,
338 pub recommendations: Vec<String>,
339}
340
341#[derive(Debug, Clone)]
343pub struct CollectionUsageInfo {
344 pub collection_type: String,
345 pub usage_pattern: String,
346 pub efficiency_rating: EfficiencyRating,
347 pub recommendations: Vec<String>,
348}
349
350#[derive(Debug, Clone)]
352pub enum EfficiencyRating {
353 Optimal,
354 Good,
355 Fair,
356 Poor,
357}
358
359#[derive(Debug, Clone)]
361pub struct MemoryPatternInfo {
362 pub pattern_type: MemoryPatternType,
363 pub impact: MemoryImpact,
364 pub location: String,
365 pub recommendations: Vec<String>,
366}
367
368#[derive(Debug, Clone)]
370pub enum MemoryPatternType {
371 MemoryLeak,
372 ExcessiveAllocation,
373 EfficientCaching,
374 PoolingPattern,
375 LazyInitialization,
376}
377
378#[derive(Debug, Clone)]
380pub enum MemoryImpact {
381 High,
382 Medium,
383 Low,
384 Positive,
385}
386
387#[derive(Debug, Clone)]
389pub struct ConcurrencyPatternInfo {
390 pub pattern_type: ConcurrencyPatternType,
391 pub thread_safety: ThreadSafety,
392 pub performance_impact: PerformanceImpact,
393 pub recommendations: Vec<String>,
394}
395
396#[derive(Debug, Clone)]
398pub enum ConcurrencyPatternType {
399 Synchronization,
400 LockFree,
401 ActorModel,
402 ForkJoin,
403 CompletableFuture,
404 Reactive,
405}
406
407#[derive(Debug, Clone)]
409pub enum ThreadSafety {
410 ThreadSafe,
411 ConditionallyThreadSafe,
412 NotThreadSafe,
413 Immutable,
414}
415
416#[derive(Debug, Clone)]
418pub struct OptimizationOpportunity {
419 pub opportunity_type: OptimizationType,
420 pub potential_impact: ImpactLevel,
421 pub description: String,
422 pub implementation_difficulty: DifficultyLevel,
423 pub recommendations: Vec<String>,
424}
425
426#[derive(Debug, Clone)]
428pub enum OptimizationType {
429 AlgorithmImprovement,
430 DataStructureOptimization,
431 ConcurrencyImprovement,
432 MemoryOptimization,
433 IOOptimization,
434 DatabaseOptimization,
435}
436
437#[derive(Debug, Clone)]
439pub enum ImpactLevel {
440 High,
441 Medium,
442 Low,
443}
444
445#[derive(Debug, Clone)]
447pub enum DifficultyLevel {
448 Easy,
449 Medium,
450 Hard,
451 VeryHard,
452}
453
454#[derive(Debug, Clone)]
456pub struct JavaFrameworkAnalysis {
457 pub frameworks_detected: Vec<FrameworkInfo>,
458 pub spring_analysis: Option<SpringAnalysis>,
459 pub hibernate_analysis: Option<HibernateAnalysis>,
460 pub junit_analysis: Option<JUnitAnalysis>,
461 pub maven_analysis: Option<MavenAnalysis>,
462 pub gradle_analysis: Option<GradleAnalysis>,
463 pub overall_framework_score: i32,
464}
465
466#[derive(Debug, Clone)]
468pub struct FrameworkInfo {
469 pub name: String,
470 pub version: Option<String>,
471 pub confidence: f32,
472 pub usage_patterns: Vec<String>,
473 pub best_practices_followed: Vec<String>,
474 pub potential_issues: Vec<String>,
475}
476
477#[derive(Debug, Clone)]
479pub struct SpringAnalysis {
480 pub spring_boot_used: bool,
481 pub components: Vec<SpringComponentInfo>,
482 pub dependency_injection: Vec<DIPatternInfo>,
483 pub aop_usage: Vec<AOPPatternInfo>,
484 pub transaction_management: Vec<TransactionInfo>,
485 pub security_configuration: Option<SpringSecurityInfo>,
486 pub data_access_patterns: Vec<DataAccessPatternInfo>,
487}
488
489#[derive(Debug, Clone)]
491pub struct SpringComponentInfo {
492 pub component_type: SpringComponentType,
493 pub class_name: String,
494 pub annotations: Vec<String>,
495 pub scope: String,
496 pub dependencies: Vec<String>,
497}
498
499#[derive(Debug, Clone)]
501pub enum SpringComponentType {
502 Component,
503 Service,
504 Repository,
505 Controller,
506 RestController,
507 Configuration,
508 Bean,
509}
510
511#[derive(Debug, Clone)]
513pub struct DIPatternInfo {
514 pub injection_type: DIType,
515 pub target_class: String,
516 pub dependencies: Vec<String>,
517 pub follows_best_practices: bool,
518 pub potential_issues: Vec<String>,
519}
520
521#[derive(Debug, Clone)]
523pub enum DIType {
524 Constructor,
525 Field,
526 Setter,
527 Method,
528}
529
530#[derive(Debug, Clone)]
532pub struct AOPPatternInfo {
533 pub aspect_class: String,
534 pub pointcuts: Vec<String>,
535 pub advice_types: Vec<AdviceType>,
536 pub cross_cutting_concerns: Vec<String>,
537}
538
539#[derive(Debug, Clone)]
541pub enum AdviceType {
542 Before,
543 After,
544 AfterReturning,
545 AfterThrowing,
546 Around,
547}
548
549#[derive(Debug, Clone)]
551pub struct TransactionInfo {
552 pub class_name: String,
553 pub method_name: String,
554 pub transaction_type: TransactionType,
555 pub propagation: String,
556 pub isolation: String,
557 pub rollback_rules: Vec<String>,
558}
559
560#[derive(Debug, Clone)]
562pub enum TransactionType {
563 Declarative,
564 Programmatic,
565}
566
567#[derive(Debug, Clone)]
569pub struct SpringSecurityInfo {
570 pub authentication_mechanisms: Vec<String>,
571 pub authorization_patterns: Vec<String>,
572 pub security_configurations: Vec<String>,
573 pub csrf_protection: bool,
574 pub session_management: String,
575}
576
577#[derive(Debug, Clone)]
579pub struct DataAccessPatternInfo {
580 pub pattern_type: DataAccessPattern,
581 pub implementation_class: String,
582 pub database_operations: Vec<String>,
583 pub query_methods: Vec<QueryMethodInfo>,
584}
585
586#[derive(Debug, Clone)]
588pub enum DataAccessPattern {
589 JpaRepository,
590 CrudRepository,
591 JdbcTemplate,
592 NamedParameterJdbcTemplate,
593 CustomRepository,
594}
595
596#[derive(Debug, Clone)]
598pub struct QueryMethodInfo {
599 pub method_name: String,
600 pub query_type: QueryType,
601 pub custom_query: Option<String>,
602 pub parameters: Vec<String>,
603 pub return_type: String,
604}
605
606#[derive(Debug, Clone)]
608pub enum QueryType {
609 DerivedQuery,
610 CustomQuery,
611 NativeQuery,
612 NamedQuery,
613}
614
615#[derive(Debug, Clone)]
617pub struct HibernateAnalysis {
618 pub entities: Vec<JPAEntityInfo>,
619 pub relationships: Vec<EntityRelationshipInfo>,
620 pub query_analysis: Vec<JPAQueryInfo>,
621 pub performance_considerations: Vec<PerformanceIssue>,
622 pub configuration_analysis: JPAConfigurationInfo,
623}
624
625#[derive(Debug, Clone)]
627pub struct JPAEntityInfo {
628 pub entity_name: String,
629 pub table_name: String,
630 pub primary_key: Vec<String>,
631 pub fields: Vec<JPAFieldInfo>,
632 pub annotations: Vec<String>,
633 pub inheritance_strategy: Option<String>,
634}
635
636#[derive(Debug, Clone)]
638pub struct JPAFieldInfo {
639 pub field_name: String,
640 pub column_name: String,
641 pub field_type: String,
642 pub constraints: Vec<String>,
643 pub annotations: Vec<String>,
644 pub relationship_type: Option<RelationshipType>,
645}
646
647#[derive(Debug, Clone)]
649pub struct EntityRelationshipInfo {
650 pub relationship_type: RelationshipType,
651 pub source_entity: String,
652 pub target_entity: String,
653 pub fetch_type: FetchType,
654 pub cascade_operations: Vec<CascadeType>,
655 pub bidirectional: bool,
656}
657
658#[derive(Debug, Clone)]
660pub enum RelationshipType {
661 OneToOne,
662 OneToMany,
663 ManyToOne,
664 ManyToMany,
665}
666
667#[derive(Debug, Clone)]
669pub enum FetchType {
670 Eager,
671 Lazy,
672}
673
674#[derive(Debug, Clone)]
676pub enum CascadeType {
677 All,
678 Persist,
679 Merge,
680 Remove,
681 Refresh,
682 Detach,
683}
684
685#[derive(Debug, Clone)]
687pub struct JPAQueryInfo {
688 pub query_type: JPAQueryType,
689 pub query_string: String,
690 pub parameters: Vec<String>,
691 pub result_type: String,
692 pub potential_issues: Vec<String>,
693}
694
695#[derive(Debug, Clone)]
697pub enum JPAQueryType {
698 JPQL,
699 NativeSQL,
700 CriteriaAPI,
701 NamedQuery,
702}
703
704#[derive(Debug, Clone)]
706pub struct PerformanceIssue {
707 pub issue_type: PerformanceIssueType,
708 pub severity: IssueSeverity,
709 pub location: String,
710 pub description: String,
711 pub recommendation: String,
712}
713
714#[derive(Debug, Clone)]
716pub enum PerformanceIssueType {
717 NPlusOneProblem,
718 LazyLoadingIssue,
719 InEfficientQuery,
720 MissingIndex,
721 CartesianProduct,
722 UnoptimizedFetch,
723 LargeResultSet,
724}
725
726#[derive(Debug, Clone)]
728pub enum IssueSeverity {
729 Critical,
730 High,
731 Medium,
732 Low,
733}
734
735#[derive(Debug, Clone)]
737pub struct JPAConfigurationInfo {
738 pub hibernate_dialect: Option<String>,
739 pub show_sql: bool,
740 pub format_sql: bool,
741 pub ddl_auto: Option<String>,
742 pub cache_configuration: Vec<String>,
743 pub connection_pool_settings: Vec<String>,
744}
745
746#[derive(Debug, Clone)]
748pub struct JUnitAnalysis {
749 pub junit_version: JUnitVersion,
750 pub test_classes: Vec<TestClassInfo>,
751 pub test_patterns: Vec<TestPatternInfo>,
752 pub mocking_frameworks: Vec<MockingFrameworkInfo>,
753 pub coverage_patterns: Vec<String>,
754 pub best_practices_score: i32,
755}
756
757#[derive(Debug, Clone)]
759pub enum JUnitVersion {
760 JUnit4,
761 JUnit5,
762 Mixed,
763 Unknown,
764}
765
766#[derive(Debug, Clone)]
768pub struct TestClassInfo {
769 pub class_name: String,
770 pub test_methods: Vec<TestMethodInfo>,
771 pub setup_methods: Vec<String>,
772 pub teardown_methods: Vec<String>,
773 pub annotations: Vec<String>,
774}
775
776#[derive(Debug, Clone)]
778pub struct TestMethodInfo {
779 pub method_name: String,
780 pub test_type: TestType,
781 pub assertions_count: usize,
782 pub expected_exceptions: Vec<String>,
783 pub timeout: Option<String>,
784 pub parameters: Vec<String>,
785}
786
787#[derive(Debug, Clone)]
789pub enum TestType {
790 Unit,
791 Integration,
792 Parameterized,
793 Performance,
794 Exception,
795}
796
797#[derive(Debug, Clone)]
799pub struct TestPatternInfo {
800 pub pattern_type: TestPatternType,
801 pub usage_count: usize,
802 pub classes_using: Vec<String>,
803}
804
805#[derive(Debug, Clone)]
807pub enum TestPatternType {
808 ArrangeActAssert,
809 GivenWhenThen,
810 TestFixture,
811 DataDriven,
812 MockObject,
813 TestDouble,
814}
815
816#[derive(Debug, Clone)]
818pub struct MockingFrameworkInfo {
819 pub framework_name: String,
820 pub version: Option<String>,
821 pub usage_patterns: Vec<String>,
822 pub mock_objects: Vec<String>,
823}
824
825#[derive(Debug, Clone)]
827pub struct MavenAnalysis {
828 pub project_info: MavenProjectInfo,
829 pub dependencies: Vec<MavenDependencyInfo>,
830 pub plugins: Vec<MavenPluginInfo>,
831 pub profiles: Vec<String>,
832 pub dependency_management: Vec<String>,
833 pub potential_issues: Vec<DependencyIssue>,
834}
835
836#[derive(Debug, Clone)]
838pub struct MavenProjectInfo {
839 pub group_id: String,
840 pub artifact_id: String,
841 pub version: String,
842 pub packaging: String,
843 pub java_version: Option<String>,
844 pub properties: Vec<String>,
845}
846
847#[derive(Debug, Clone)]
849pub struct MavenDependencyInfo {
850 pub group_id: String,
851 pub artifact_id: String,
852 pub version: String,
853 pub scope: String,
854 pub dependency_type: String,
855 pub transitive_dependencies: Vec<String>,
856}
857
858#[derive(Debug, Clone)]
860pub struct MavenPluginInfo {
861 pub group_id: String,
862 pub artifact_id: String,
863 pub version: Option<String>,
864 pub configuration: Vec<String>,
865 pub executions: Vec<String>,
866}
867
868#[derive(Debug, Clone)]
870pub struct DependencyIssue {
871 pub issue_type: DependencyIssueType,
872 pub affected_dependencies: Vec<String>,
873 pub severity: IssueSeverity,
874 pub description: String,
875 pub recommendation: String,
876}
877
878#[derive(Debug, Clone)]
880pub enum DependencyIssueType {
881 VersionConflict,
882 SecurityVulnerability,
883 DeprecatedDependency,
884 UnusedDependency,
885 TransitiveDependencyIssue,
886 LicenseIncompatibility,
887}
888
889#[derive(Debug, Clone)]
891pub struct GradleAnalysis {
892 pub project_info: GradleProjectInfo,
893 pub dependencies: Vec<GradleDependencyInfo>,
894 pub plugins: Vec<GradlePluginInfo>,
895 pub tasks: Vec<GradleTaskInfo>,
896 pub build_configurations: Vec<String>,
897 pub potential_issues: Vec<DependencyIssue>,
898}
899
900#[derive(Debug, Clone)]
902pub struct GradleProjectInfo {
903 pub project_name: String,
904 pub version: String,
905 pub java_version: Option<String>,
906 pub gradle_version: Option<String>,
907 pub source_compatibility: Option<String>,
908 pub target_compatibility: Option<String>,
909}
910
911#[derive(Debug, Clone)]
913pub struct GradleDependencyInfo {
914 pub configuration: String,
915 pub group: String,
916 pub name: String,
917 pub version: String,
918 pub dependency_type: String,
919}
920
921#[derive(Debug, Clone)]
923pub struct GradlePluginInfo {
924 pub plugin_id: String,
925 pub version: Option<String>,
926 pub apply: bool,
927 pub configuration: Vec<String>,
928}
929
930#[derive(Debug, Clone)]
932pub struct GradleTaskInfo {
933 pub task_name: String,
934 pub task_type: String,
935 pub dependencies: Vec<String>,
936 pub description: String,
937}
938
939#[derive(Debug, Clone)]
941pub struct JavaSecurityAnalysis {
942 pub security_level: SecurityLevel,
943 pub vulnerabilities: Vec<SecurityVulnerability>,
944 pub security_patterns: Vec<SecurityPattern>,
945 pub authentication_analysis: Vec<AuthenticationPattern>,
946 pub authorization_analysis: Vec<AuthorizationPattern>,
947 pub input_validation_analysis: Vec<InputValidationPattern>,
948 pub cryptographic_analysis: Vec<CryptographicPattern>,
949 pub web_security_analysis: Vec<WebSecurityPattern>,
950 pub recommendations: Vec<String>,
951}
952
953#[derive(Debug, Clone)]
955pub enum SecurityLevel {
956 High,
957 Medium,
958 Low,
959 Vulnerable,
960}
961
962#[derive(Debug, Clone)]
964pub struct SecurityVulnerability {
965 pub vulnerability_type: SecurityVulnerabilityType,
966 pub severity: SecuritySeverity,
967 pub location: String,
968 pub description: String,
969 pub cwe_id: Option<String>,
970 pub recommendation: String,
971}
972
973#[derive(Debug, Clone)]
975pub enum SecurityVulnerabilityType {
976 SqlInjection,
977 XssVulnerability,
978 CommandInjection,
979 PathTraversal,
980 DeserializationAttack,
981 WeakCryptography,
982 HardcodedCredentials,
983 InsecureRandomness,
984 UnvalidatedRedirect,
985 SessionFixation,
986 CsrfVulnerability,
987 XXEVulnerability,
988 LdapInjection,
989 InsecureDirectObjectReference,
990}
991
992#[derive(Debug, Clone)]
994pub enum SecuritySeverity {
995 Critical,
996 High,
997 Medium,
998 Low,
999 Info,
1000}
1001
1002#[derive(Debug, Clone)]
1004pub struct SecurityPattern {
1005 pub pattern_type: SecurityPatternType,
1006 pub implementation_quality: ImplementationQuality,
1007 pub location: String,
1008 pub description: String,
1009}
1010
1011#[derive(Debug, Clone)]
1013pub enum SecurityPatternType {
1014 SecureAuthentication,
1015 RoleBasedAccess,
1016 InputSanitization,
1017 OutputEncoding,
1018 SecureCommunication,
1019 AuditLogging,
1020 ErrorHandling,
1021 SessionManagement,
1022}
1023
1024#[derive(Debug, Clone)]
1026pub struct AuthenticationPattern {
1027 pub authentication_type: AuthenticationType,
1028 pub implementation_class: String,
1029 pub security_features: Vec<String>,
1030 pub weaknesses: Vec<String>,
1031}
1032
1033#[derive(Debug, Clone)]
1035pub enum AuthenticationType {
1036 FormBased,
1037 BasicAuth,
1038 DigestAuth,
1039 JwtToken,
1040 OAuth2,
1041 SAML,
1042 Custom,
1043}
1044
1045#[derive(Debug, Clone)]
1047pub struct AuthorizationPattern {
1048 pub authorization_type: AuthorizationType,
1049 pub roles: Vec<String>,
1050 pub permissions: Vec<String>,
1051 pub access_control_rules: Vec<String>,
1052}
1053
1054#[derive(Debug, Clone)]
1056pub enum AuthorizationType {
1057 RoleBased,
1058 AttributeBased,
1059 PermissionBased,
1060 ResourceBased,
1061 Custom,
1062}
1063
1064#[derive(Debug, Clone)]
1066pub struct InputValidationPattern {
1067 pub validation_type: ValidationType,
1068 pub input_sources: Vec<String>,
1069 pub validation_methods: Vec<String>,
1070 pub sanitization_techniques: Vec<String>,
1071}
1072
1073#[derive(Debug, Clone)]
1075pub enum ValidationType {
1076 Whitelist,
1077 Blacklist,
1078 RegexValidation,
1079 TypeValidation,
1080 RangeValidation,
1081 Custom,
1082}
1083
1084#[derive(Debug, Clone)]
1086pub struct CryptographicPattern {
1087 pub crypto_operation: CryptographicOperation,
1088 pub algorithm: String,
1089 pub key_management: KeyManagementPattern,
1090 pub implementation_issues: Vec<String>,
1091}
1092
1093#[derive(Debug, Clone)]
1095pub enum CryptographicOperation {
1096 Encryption,
1097 Decryption,
1098 Hashing,
1099 DigitalSignature,
1100 KeyGeneration,
1101 KeyExchange,
1102}
1103
1104#[derive(Debug, Clone)]
1106pub struct KeyManagementPattern {
1107 pub key_storage: KeyStorageType,
1108 pub key_rotation: bool,
1109 pub key_strength: KeyStrength,
1110 pub key_derivation: Option<String>,
1111}
1112
1113#[derive(Debug, Clone)]
1115pub enum KeyStorageType {
1116 Keystore,
1117 HSM, Configuration,
1119 Hardcoded,
1120 Environment,
1121 Database,
1122}
1123
1124#[derive(Debug, Clone)]
1126pub enum KeyStrength {
1127 Strong,
1128 Adequate,
1129 Weak,
1130 Unknown,
1131}
1132
1133#[derive(Debug, Clone)]
1135pub struct WebSecurityPattern {
1136 pub security_mechanism: WebSecurityMechanism,
1137 pub configuration: Vec<String>,
1138 pub effectiveness: SecurityEffectiveness,
1139}
1140
1141#[derive(Debug, Clone)]
1143pub enum WebSecurityMechanism {
1144 CsrfProtection,
1145 XssProtection,
1146 ContentSecurityPolicy,
1147 HttpsEnforcement,
1148 SecureHeaders,
1149 SessionSecurity,
1150 CorsConfiguration,
1151}
1152
1153#[derive(Debug, Clone)]
1155pub enum SecurityEffectiveness {
1156 Excellent,
1157 Good,
1158 Adequate,
1159 Poor,
1160 Missing,
1161}
1162
1163#[derive(Debug, Clone)]
1165pub struct ModernJavaFeatureAnalysis {
1166 pub java_version_detected: JavaVersionInfo,
1167 pub lambda_expressions: Vec<LambdaExpressionInfo>,
1168 pub stream_api_usage: Vec<StreamApiUsageInfo>,
1169 pub optional_usage: Vec<OptionalUsageInfo>,
1170 pub module_system_usage: Option<ModuleSystemInfo>,
1171 pub record_classes: Vec<RecordClassInfo>,
1172 pub sealed_classes: Vec<SealedClassInfo>,
1173 pub switch_expressions: Vec<SwitchExpressionInfo>,
1174 pub text_blocks: Vec<TextBlockInfo>,
1175 pub var_keyword_usage: Vec<VarUsageInfo>,
1176 pub completable_future_usage: Vec<CompletableFutureInfo>,
1177 pub date_time_api_usage: Vec<DateTimeApiInfo>,
1178 pub collection_factory_methods: Vec<CollectionFactoryInfo>,
1179 pub overall_modernity_score: i32,
1180}
1181
1182#[derive(Debug, Clone)]
1184pub struct JavaVersionInfo {
1185 pub minimum_version_required: String,
1186 pub features_by_version: Vec<VersionFeatureInfo>,
1187 pub compatibility_issues: Vec<CompatibilityIssue>,
1188}
1189
1190#[derive(Debug, Clone)]
1192pub struct VersionFeatureInfo {
1193 pub feature_name: String,
1194 pub java_version: String,
1195 pub usage_count: usize,
1196 pub is_best_practice: bool,
1197}
1198
1199#[derive(Debug, Clone)]
1201pub struct CompatibilityIssue {
1202 pub issue_type: CompatibilityIssueType,
1203 pub required_version: String,
1204 pub current_version: String,
1205 pub affected_features: Vec<String>,
1206}
1207
1208#[derive(Debug, Clone)]
1210pub enum CompatibilityIssueType {
1211 VersionMismatch,
1212 DeprecatedFeature,
1213 NewApiUsage,
1214 UnsupportedFeature,
1215}
1216
1217#[derive(Debug, Clone)]
1219pub struct LambdaExpressionInfo {
1220 pub expression: String,
1221 pub functional_interface: String,
1222 pub complexity: LambdaComplexity,
1223 pub captures_variables: bool,
1224 pub usage_context: String,
1225 pub performance_impact: PerformanceImpact,
1226}
1227
1228#[derive(Debug, Clone)]
1230pub enum PerformanceImpact {
1231 Positive,
1232 Neutral,
1233 Negative,
1234}
1235
1236#[derive(Debug, Clone)]
1238pub struct StreamApiUsageInfo {
1239 pub stream_source: String,
1240 pub operations: Vec<StreamOperation>,
1241 pub terminal_operation: String,
1242 pub parallel_usage: bool,
1243 pub performance_characteristics: StreamPerformance,
1244 pub complexity: StreamComplexity,
1245}
1246
1247#[derive(Debug, Clone)]
1249pub struct StreamOperation {
1250 pub operation_type: StreamOperationType,
1251 pub operation_name: String,
1252 pub parameters: Vec<String>,
1253}
1254
1255#[derive(Debug, Clone)]
1257pub enum StreamOperationType {
1258 Intermediate,
1259 Terminal,
1260}
1261
1262#[derive(Debug, Clone)]
1264pub enum StreamPerformance {
1265 Optimal,
1266 Good,
1267 Fair,
1268 Poor,
1269}
1270
1271#[derive(Debug, Clone)]
1273pub enum StreamComplexity {
1274 Simple,
1275 Moderate,
1276 Complex,
1277 VeryComplex,
1278}
1279
1280#[derive(Debug, Clone)]
1282pub struct OptionalUsageInfo {
1283 pub usage_context: String,
1284 pub optional_type: String,
1285 pub usage_pattern: OptionalUsagePattern,
1286 pub anti_patterns: Vec<OptionalAntiPattern>,
1287}
1288
1289#[derive(Debug, Clone)]
1291pub enum OptionalUsagePattern {
1292 ReturnValue,
1293 FieldValue,
1294 ParameterValue,
1295 ChainedCalls,
1296}
1297
1298#[derive(Debug, Clone)]
1300pub enum OptionalAntiPattern {
1301 CallingGet,
1302 UsingIsPresent,
1303 ReturningNull,
1304 UsingInFields,
1305}
1306
1307#[derive(Debug, Clone)]
1309pub struct ModuleSystemInfo {
1310 pub module_name: String,
1311 pub exports: Vec<String>,
1312 pub requires: Vec<String>,
1313 pub provides: Vec<String>,
1314 pub uses: Vec<String>,
1315 pub opens: Vec<String>,
1316}
1317
1318#[derive(Debug, Clone)]
1320pub struct RecordClassInfo {
1321 pub record_name: String,
1322 pub components: Vec<RecordComponent>,
1323 pub additional_methods: Vec<String>,
1324 pub implements_interfaces: Vec<String>,
1325}
1326
1327#[derive(Debug, Clone)]
1329pub struct RecordComponent {
1330 pub name: String,
1331 pub component_type: String,
1332 pub annotations: Vec<String>,
1333}
1334
1335#[derive(Debug, Clone)]
1337pub struct SealedClassInfo {
1338 pub sealed_class_name: String,
1339 pub permitted_subclasses: Vec<String>,
1340 pub sealing_type: SealingType,
1341}
1342
1343#[derive(Debug, Clone)]
1345pub enum SealingType {
1346 SealedClass,
1347 SealedInterface,
1348}
1349
1350#[derive(Debug, Clone)]
1352pub struct SwitchExpressionInfo {
1353 pub switch_type: String,
1354 pub has_yield: bool,
1355 pub pattern_matching: bool,
1356 pub exhaustiveness: bool,
1357 pub arrow_syntax: bool,
1358}
1359
1360#[derive(Debug, Clone)]
1362pub struct TextBlockInfo {
1363 pub content_type: TextBlockContentType,
1364 pub line_count: usize,
1365 pub indentation_stripped: bool,
1366 pub escape_sequences_used: Vec<String>,
1367}
1368
1369#[derive(Debug, Clone)]
1371pub enum TextBlockContentType {
1372 Json,
1373 Xml,
1374 Html,
1375 Sql,
1376 PlainText,
1377 Other,
1378}
1379
1380#[derive(Debug, Clone)]
1382pub struct VarUsageInfo {
1383 pub usage_context: VarUsageContext,
1384 pub inferred_type: String,
1385 pub appropriate_usage: bool,
1386}
1387
1388#[derive(Debug, Clone)]
1390pub enum VarUsageContext {
1391 LocalVariable,
1392 ForLoop,
1393 TryWithResources,
1394 LambdaParameter,
1395}
1396
1397#[derive(Debug, Clone)]
1399pub struct CompletableFutureInfo {
1400 pub usage_pattern: CompletableFuturePattern,
1401 pub chaining_complexity: i32,
1402 pub exception_handling: bool,
1403 pub thread_pool_usage: Option<String>,
1404}
1405
1406#[derive(Debug, Clone)]
1408pub enum CompletableFuturePattern {
1409 SimpleAsync,
1410 Chaining,
1411 Combining,
1412 ExceptionHandling,
1413 CustomExecutor,
1414}
1415
1416#[derive(Debug, Clone)]
1418pub struct DateTimeApiInfo {
1419 pub api_type: DateTimeApiType,
1420 pub usage_patterns: Vec<String>,
1421 pub timezone_handling: bool,
1422 pub formatting_patterns: Vec<String>,
1423}
1424
1425#[derive(Debug, Clone)]
1427pub enum DateTimeApiType {
1428 LocalDateTime,
1429 ZonedDateTime,
1430 Instant,
1431 Duration,
1432 Period,
1433 DateTimeFormatter,
1434 Legacy, }
1436
1437#[derive(Debug, Clone)]
1439pub struct CollectionFactoryInfo {
1440 pub factory_method: String,
1441 pub collection_type: String,
1442 pub element_count: usize,
1443 pub immutability: bool,
1444}
1445
1446#[derive(Debug)]
1448pub struct JavaAnalyzer {
1449 oop_patterns: HashMap<String, Vec<OOPPattern>>,
1451 framework_patterns: HashMap<String, Vec<FrameworkPattern>>,
1452 security_patterns: HashMap<String, Vec<SecurityAnalysisPattern>>,
1453 modern_feature_patterns: HashMap<String, Vec<ModernFeaturePattern>>,
1454}
1455
1456#[derive(Debug)]
1458struct OOPPattern {
1459 name: String,
1460 pattern: Regex,
1461 pattern_type: String,
1462 confidence_weight: f32,
1463}
1464
1465#[derive(Debug)]
1466struct FrameworkPattern {
1467 name: String,
1468 pattern: Regex,
1469 framework: String,
1470 confidence_weight: f32,
1471}
1472
1473#[derive(Debug)]
1474struct SecurityAnalysisPattern {
1475 name: String,
1476 pattern: Regex,
1477 vulnerability_type: String,
1478 severity: String,
1479}
1480
1481#[derive(Debug)]
1482struct ModernFeaturePattern {
1483 name: String,
1484 pattern: Regex,
1485 java_version: String,
1486 feature_type: String,
1487}
1488
1489impl JavaAnalyzer {
1490 pub fn new() -> Self {
1492 let mut analyzer = Self {
1493 oop_patterns: HashMap::new(),
1494 framework_patterns: HashMap::new(),
1495 security_patterns: HashMap::new(),
1496 modern_feature_patterns: HashMap::new(),
1497 };
1498
1499 analyzer.initialize_patterns();
1500 analyzer
1501 }
1502
1503 fn initialize_patterns(&mut self) {
1505 self.initialize_oop_patterns();
1506 self.initialize_framework_patterns();
1507 self.initialize_security_patterns();
1508 self.initialize_modern_feature_patterns();
1509 }
1510
1511 fn initialize_oop_patterns(&mut self) {
1513 let mut patterns = Vec::new();
1514
1515 patterns.push(OOPPattern {
1517 name: "singleton_private_constructor".to_string(),
1518 pattern: Regex::new(r"private\s+\w+\s*\(\s*\)").unwrap(),
1519 pattern_type: "singleton".to_string(),
1520 confidence_weight: 0.6,
1521 });
1522
1523 patterns.push(OOPPattern {
1524 name: "singleton_instance_method".to_string(),
1525 pattern: Regex::new(r"public\s+static\s+\w+\s+getInstance\s*\(\s*\)").unwrap(),
1526 pattern_type: "singleton".to_string(),
1527 confidence_weight: 0.8,
1528 });
1529
1530 patterns.push(OOPPattern {
1532 name: "factory_method".to_string(),
1533 pattern: Regex::new(r"public\s+static\s+\w+\s+create\w*\s*\(").unwrap(),
1534 pattern_type: "factory".to_string(),
1535 confidence_weight: 0.7,
1536 });
1537
1538 patterns.push(OOPPattern {
1540 name: "builder_method".to_string(),
1541 pattern: Regex::new(
1542 r"public\s+\w+\s+\w+\s*\([^)]*\)\s*\{\s*\w+\.\w+\s*=.*return\s+this",
1543 )
1544 .unwrap(),
1545 pattern_type: "builder".to_string(),
1546 confidence_weight: 0.8,
1547 });
1548
1549 patterns.push(OOPPattern {
1551 name: "observer_notify".to_string(),
1552 pattern: Regex::new(r"notify(All)?Observers?\s*\(").unwrap(),
1553 pattern_type: "observer".to_string(),
1554 confidence_weight: 0.9,
1555 });
1556
1557 patterns.push(OOPPattern {
1559 name: "decorator_composition".to_string(),
1560 pattern: Regex::new(r"private\s+final\s+\w+\s+\w+").unwrap(),
1561 pattern_type: "decorator".to_string(),
1562 confidence_weight: 0.5,
1563 });
1564
1565 patterns.push(OOPPattern {
1567 name: "class_extends".to_string(),
1568 pattern: Regex::new(r"class\s+(\w+)\s+extends\s+(\w+)").unwrap(),
1569 pattern_type: "inheritance".to_string(),
1570 confidence_weight: 1.0,
1571 });
1572
1573 patterns.push(OOPPattern {
1574 name: "implements_interface".to_string(),
1575 pattern: Regex::new(r"class\s+(\w+).*implements\s+([\w\s,]+)").unwrap(),
1576 pattern_type: "interface_implementation".to_string(),
1577 confidence_weight: 1.0,
1578 });
1579
1580 patterns.push(OOPPattern {
1582 name: "method_override".to_string(),
1583 pattern: Regex::new(r"@Override\s+public\s+\w+\s+(\w+)\s*\(").unwrap(),
1584 pattern_type: "polymorphism".to_string(),
1585 confidence_weight: 1.0,
1586 });
1587
1588 patterns.push(OOPPattern {
1590 name: "private_field".to_string(),
1591 pattern: Regex::new(r"private\s+\w+\s+\w+").unwrap(),
1592 pattern_type: "encapsulation".to_string(),
1593 confidence_weight: 0.8,
1594 });
1595
1596 patterns.push(OOPPattern {
1597 name: "getter_method".to_string(),
1598 pattern: Regex::new(r"public\s+\w+\s+get(\w+)\s*\(\s*\)").unwrap(),
1599 pattern_type: "encapsulation".to_string(),
1600 confidence_weight: 0.9,
1601 });
1602
1603 patterns.push(OOPPattern {
1604 name: "setter_method".to_string(),
1605 pattern: Regex::new(r"public\s+void\s+set(\w+)\s*\(\s*\w+\s+\w+\s*\)").unwrap(),
1606 pattern_type: "encapsulation".to_string(),
1607 confidence_weight: 0.9,
1608 });
1609
1610 self.oop_patterns
1611 .insert("design_patterns".to_string(), patterns);
1612 }
1613
1614 fn initialize_framework_patterns(&mut self) {
1616 let mut spring_patterns = Vec::new();
1617
1618 spring_patterns.push(FrameworkPattern {
1620 name: "spring_component".to_string(),
1621 pattern: Regex::new(r"@Component").unwrap(),
1622 framework: "Spring".to_string(),
1623 confidence_weight: 0.9,
1624 });
1625
1626 spring_patterns.push(FrameworkPattern {
1627 name: "spring_service".to_string(),
1628 pattern: Regex::new(r"@Service").unwrap(),
1629 framework: "Spring".to_string(),
1630 confidence_weight: 0.9,
1631 });
1632
1633 spring_patterns.push(FrameworkPattern {
1634 name: "spring_repository".to_string(),
1635 pattern: Regex::new(r"@Repository").unwrap(),
1636 framework: "Spring".to_string(),
1637 confidence_weight: 0.9,
1638 });
1639
1640 spring_patterns.push(FrameworkPattern {
1641 name: "spring_controller".to_string(),
1642 pattern: Regex::new(r"@(Rest)?Controller").unwrap(),
1643 framework: "Spring".to_string(),
1644 confidence_weight: 0.9,
1645 });
1646
1647 spring_patterns.push(FrameworkPattern {
1648 name: "spring_autowired".to_string(),
1649 pattern: Regex::new(r"@Autowired").unwrap(),
1650 framework: "Spring".to_string(),
1651 confidence_weight: 0.8,
1652 });
1653
1654 spring_patterns.push(FrameworkPattern {
1655 name: "spring_transactional".to_string(),
1656 pattern: Regex::new(r"@Transactional").unwrap(),
1657 framework: "Spring".to_string(),
1658 confidence_weight: 0.8,
1659 });
1660
1661 let mut jpa_patterns = Vec::new();
1663
1664 jpa_patterns.push(FrameworkPattern {
1665 name: "jpa_entity".to_string(),
1666 pattern: Regex::new(r"@Entity").unwrap(),
1667 framework: "JPA".to_string(),
1668 confidence_weight: 0.9,
1669 });
1670
1671 jpa_patterns.push(FrameworkPattern {
1672 name: "jpa_table".to_string(),
1673 pattern: Regex::new(r"@Table").unwrap(),
1674 framework: "JPA".to_string(),
1675 confidence_weight: 0.8,
1676 });
1677
1678 jpa_patterns.push(FrameworkPattern {
1679 name: "jpa_id".to_string(),
1680 pattern: Regex::new(r"@Id").unwrap(),
1681 framework: "JPA".to_string(),
1682 confidence_weight: 0.9,
1683 });
1684
1685 jpa_patterns.push(FrameworkPattern {
1686 name: "jpa_column".to_string(),
1687 pattern: Regex::new(r"@Column").unwrap(),
1688 framework: "JPA".to_string(),
1689 confidence_weight: 0.7,
1690 });
1691
1692 let mut junit_patterns = Vec::new();
1694
1695 junit_patterns.push(FrameworkPattern {
1696 name: "junit_test".to_string(),
1697 pattern: Regex::new(r"@Test").unwrap(),
1698 framework: "JUnit".to_string(),
1699 confidence_weight: 0.9,
1700 });
1701
1702 junit_patterns.push(FrameworkPattern {
1703 name: "junit_before".to_string(),
1704 pattern: Regex::new(r"@Before(Each)?").unwrap(),
1705 framework: "JUnit".to_string(),
1706 confidence_weight: 0.8,
1707 });
1708
1709 junit_patterns.push(FrameworkPattern {
1710 name: "junit_after".to_string(),
1711 pattern: Regex::new(r"@After(Each)?").unwrap(),
1712 framework: "JUnit".to_string(),
1713 confidence_weight: 0.8,
1714 });
1715
1716 self.framework_patterns
1717 .insert("Spring".to_string(), spring_patterns);
1718 self.framework_patterns
1719 .insert("JPA".to_string(), jpa_patterns);
1720 self.framework_patterns
1721 .insert("JUnit".to_string(), junit_patterns);
1722 }
1723
1724 fn initialize_security_patterns(&mut self) {
1726 let mut patterns = Vec::new();
1727
1728 patterns.push(SecurityAnalysisPattern {
1730 name: "sql_concatenation".to_string(),
1731 pattern: Regex::new(r#"(SELECT|INSERT|UPDATE|DELETE).*\+.*["']"#).unwrap(),
1732 vulnerability_type: "sql_injection".to_string(),
1733 severity: "high".to_string(),
1734 });
1735
1736 patterns.push(SecurityAnalysisPattern {
1738 name: "hardcoded_password".to_string(),
1739 pattern: Regex::new(r#"(password|pwd|pass)\s*=\s*["'][^"']+["']"#).unwrap(),
1740 vulnerability_type: "hardcoded_credentials".to_string(),
1741 severity: "critical".to_string(),
1742 });
1743
1744 patterns.push(SecurityAnalysisPattern {
1746 name: "runtime_exec".to_string(),
1747 pattern: Regex::new(r"Runtime\.getRuntime\(\)\.exec\(").unwrap(),
1748 vulnerability_type: "command_injection".to_string(),
1749 severity: "high".to_string(),
1750 });
1751
1752 patterns.push(SecurityAnalysisPattern {
1754 name: "file_path_concat".to_string(),
1755 pattern: Regex::new(r"new\s+File\([^)]*\+").unwrap(),
1756 vulnerability_type: "path_traversal".to_string(),
1757 severity: "medium".to_string(),
1758 });
1759
1760 patterns.push(SecurityAnalysisPattern {
1762 name: "weak_hash".to_string(),
1763 pattern: Regex::new(r#"MessageDigest\.getInstance\(["'](MD5|SHA1)["']\)"#).unwrap(),
1764 vulnerability_type: "weak_cryptography".to_string(),
1765 severity: "medium".to_string(),
1766 });
1767
1768 patterns.push(SecurityAnalysisPattern {
1770 name: "insecure_random".to_string(),
1771 pattern: Regex::new(r"new\s+Random\(\)").unwrap(),
1772 vulnerability_type: "insecure_randomness".to_string(),
1773 severity: "low".to_string(),
1774 });
1775
1776 self.security_patterns
1777 .insert("vulnerabilities".to_string(), patterns);
1778 }
1779
1780 fn initialize_modern_feature_patterns(&mut self) {
1782 let mut patterns = Vec::new();
1783
1784 patterns.push(ModernFeaturePattern {
1786 name: "lambda_expression".to_string(),
1787 pattern: Regex::new(r"\([^)]*\)\s*->").unwrap(),
1788 java_version: "8".to_string(),
1789 feature_type: "lambda".to_string(),
1790 });
1791
1792 patterns.push(ModernFeaturePattern {
1794 name: "stream_api".to_string(),
1795 pattern: Regex::new(r"\.stream\(\)").unwrap(),
1796 java_version: "8".to_string(),
1797 feature_type: "stream".to_string(),
1798 });
1799
1800 patterns.push(ModernFeaturePattern {
1802 name: "optional_usage".to_string(),
1803 pattern: Regex::new(r"Optional<").unwrap(),
1804 java_version: "8".to_string(),
1805 feature_type: "optional".to_string(),
1806 });
1807
1808 patterns.push(ModernFeaturePattern {
1810 name: "var_keyword".to_string(),
1811 pattern: Regex::new(r"\bvar\s+\w+\s*=").unwrap(),
1812 java_version: "10".to_string(),
1813 feature_type: "var".to_string(),
1814 });
1815
1816 patterns.push(ModernFeaturePattern {
1818 name: "switch_expression".to_string(),
1819 pattern: Regex::new(r"switch\s*\([^)]+\)\s*\{[^}]*->").unwrap(),
1820 java_version: "12".to_string(),
1821 feature_type: "switch_expression".to_string(),
1822 });
1823
1824 patterns.push(ModernFeaturePattern {
1826 name: "text_blocks".to_string(),
1827 pattern: Regex::new(r#""{3}"#).unwrap(),
1828 java_version: "13".to_string(),
1829 feature_type: "text_block".to_string(),
1830 });
1831
1832 patterns.push(ModernFeaturePattern {
1834 name: "record_class".to_string(),
1835 pattern: Regex::new(r"record\s+(\w+)").unwrap(),
1836 java_version: "14".to_string(),
1837 feature_type: "record".to_string(),
1838 });
1839
1840 patterns.push(ModernFeaturePattern {
1842 name: "sealed_class".to_string(),
1843 pattern: Regex::new(r"sealed\s+(class|interface)").unwrap(),
1844 java_version: "15".to_string(),
1845 feature_type: "sealed".to_string(),
1846 });
1847
1848 self.modern_feature_patterns
1849 .insert("java_features".to_string(), patterns);
1850 }
1851
1852 pub fn analyze_comprehensive(&self, content: &str) -> Result<JavaComprehensiveAnalysis> {
1854 let oop_analysis = self.analyze_oop_patterns(content)?;
1855 let framework_analysis = self.analyze_frameworks(content)?;
1856 let security_analysis = self.analyze_security(content)?;
1857 let modern_features = self.analyze_modern_features(content)?;
1858 let performance_analysis = self.analyze_performance(content)?;
1859
1860 Ok(JavaComprehensiveAnalysis {
1861 oop_analysis,
1862 framework_analysis,
1863 security_analysis,
1864 modern_features,
1865 performance_analysis,
1866 overall_score: self.calculate_overall_score(content),
1867 })
1868 }
1869
1870 pub fn analyze_oop_patterns(&self, content: &str) -> Result<OOPAnalysisInfo> {
1872 let class_hierarchies = self.analyze_class_hierarchies(content)?;
1873 let design_patterns = self.detect_design_patterns(content)?;
1874 let encapsulation_analysis = self.analyze_encapsulation(content)?;
1875 let polymorphism_usage = self.analyze_polymorphism(content)?;
1876 let inheritance_patterns = self.analyze_inheritance_patterns(content)?;
1877 let interface_usage = self.analyze_interface_usage(content)?;
1878 let solid_principles_score = self.evaluate_solid_principles(content)?;
1879
1880 Ok(OOPAnalysisInfo {
1881 class_hierarchies,
1882 design_patterns,
1883 encapsulation_analysis,
1884 polymorphism_usage,
1885 inheritance_patterns,
1886 interface_usage,
1887 solid_principles_score,
1888 })
1889 }
1890
1891 pub fn analyze_frameworks(&self, content: &str) -> Result<JavaFrameworkAnalysis> {
1893 let frameworks_detected = self.detect_frameworks(content)?;
1894 let spring_analysis = self.analyze_spring_framework(content)?;
1895 let hibernate_analysis = self.analyze_hibernate(content)?;
1896 let junit_analysis = self.analyze_junit(content)?;
1897 let maven_analysis = self.analyze_maven(content)?;
1898 let gradle_analysis = self.analyze_gradle(content)?;
1899 let overall_framework_score = self.calculate_framework_score(&frameworks_detected);
1900
1901 Ok(JavaFrameworkAnalysis {
1902 frameworks_detected,
1903 spring_analysis,
1904 hibernate_analysis,
1905 junit_analysis,
1906 maven_analysis,
1907 gradle_analysis,
1908 overall_framework_score,
1909 })
1910 }
1911
1912 pub fn analyze_security(&self, content: &str) -> Result<JavaSecurityAnalysis> {
1914 let vulnerabilities = self.detect_vulnerabilities(content)?;
1915 let security_patterns = self.detect_security_patterns(content)?;
1916 let authentication_analysis = self.analyze_authentication(content)?;
1917 let authorization_analysis = self.analyze_authorization(content)?;
1918 let input_validation_analysis = self.analyze_input_validation(content)?;
1919 let cryptographic_analysis = self.analyze_cryptography(content)?;
1920 let web_security_analysis = self.analyze_web_security(content)?;
1921 let security_level = self.determine_security_level(&vulnerabilities, &security_patterns);
1922 let recommendations =
1923 self.generate_security_recommendations(&vulnerabilities, &security_patterns);
1924
1925 Ok(JavaSecurityAnalysis {
1926 security_level,
1927 vulnerabilities,
1928 security_patterns,
1929 authentication_analysis,
1930 authorization_analysis,
1931 input_validation_analysis,
1932 cryptographic_analysis,
1933 web_security_analysis,
1934 recommendations,
1935 })
1936 }
1937
1938 pub fn analyze_modern_features(&self, content: &str) -> Result<ModernJavaFeatureAnalysis> {
1940 let java_version_detected = self.detect_java_version(content)?;
1941 let lambda_expressions = self.analyze_lambda_expressions(content)?;
1942 let stream_api_usage = self.analyze_stream_api(content)?;
1943 let optional_usage = self.analyze_optional_usage(content)?;
1944 let module_system_usage = self.analyze_module_system(content)?;
1945 let record_classes = self.analyze_record_classes(content)?;
1946 let sealed_classes = self.analyze_sealed_classes(content)?;
1947 let switch_expressions = self.analyze_switch_expressions(content)?;
1948 let text_blocks = self.analyze_text_blocks(content)?;
1949 let var_keyword_usage = self.analyze_var_usage(content)?;
1950 let completable_future_usage = self.analyze_completable_future(content)?;
1951 let date_time_api_usage = self.analyze_date_time_api(content)?;
1952 let collection_factory_methods = self.analyze_collection_factories(content)?;
1953 let overall_modernity_score = self.calculate_modernity_score(content);
1954
1955 Ok(ModernJavaFeatureAnalysis {
1956 java_version_detected,
1957 lambda_expressions,
1958 stream_api_usage,
1959 optional_usage,
1960 module_system_usage,
1961 record_classes,
1962 sealed_classes,
1963 switch_expressions,
1964 text_blocks,
1965 var_keyword_usage,
1966 completable_future_usage,
1967 date_time_api_usage,
1968 collection_factory_methods,
1969 overall_modernity_score,
1970 })
1971 }
1972
1973 pub fn analyze_code(&self, content: &str) -> JavaAnalysisResult {
1975 let mut oop_patterns = Vec::new();
1977 let mut design_patterns = Vec::new();
1978 let mut framework_usage = Vec::new();
1979 let mut security_issues = Vec::new();
1980 let mut performance_notes = Vec::new();
1981 let mut modern_features = Vec::new();
1982
1983 if let Ok(comprehensive) = self.analyze_comprehensive(content) {
1985 for class_hierarchy in &comprehensive.oop_analysis.class_hierarchies {
1987 oop_patterns.push(format!(
1988 "Class hierarchy: {} (depth: {})",
1989 class_hierarchy.class_name, class_hierarchy.hierarchy_depth
1990 ));
1991 }
1992
1993 for pattern in &comprehensive.oop_analysis.design_patterns {
1995 design_patterns.push(format!(
1996 "{:?} pattern detected with {:.1}% confidence",
1997 pattern.pattern_type,
1998 pattern.confidence * 100.0
1999 ));
2000 }
2001
2002 for framework in &comprehensive.framework_analysis.frameworks_detected {
2004 framework_usage.push(format!(
2005 "{} framework detected (confidence: {:.1}%)",
2006 framework.name,
2007 framework.confidence * 100.0
2008 ));
2009 }
2010
2011 for vuln in &comprehensive.security_analysis.vulnerabilities {
2013 security_issues.push(format!(
2014 "{:?}: {}",
2015 vuln.vulnerability_type, vuln.description
2016 ));
2017 }
2018
2019 for issue in &comprehensive.performance_analysis.performance_issues {
2021 performance_notes.push(format!("{:?}: {}", issue.issue_type, &issue.description));
2022 }
2023
2024 for lambda in &comprehensive.modern_features.lambda_expressions {
2026 modern_features.push(format!("Lambda expression: {}", &lambda.expression));
2027 }
2028
2029 for rec in &comprehensive.security_analysis.recommendations {
2031 security_issues.push(format!("Recommendation: {rec}"));
2032 }
2033 }
2034
2035 if design_patterns.is_empty() {
2037 if content.contains("public static final") {
2038 design_patterns.push("Constants pattern detected".to_string());
2039 }
2040 if content.contains("private static") && content.contains("getInstance") {
2041 design_patterns.push("Singleton pattern detected".to_string());
2042 }
2043 }
2044
2045 let complexity_score = if content.len() > 10000 {
2047 80
2048 } else if content.len() > 5000 {
2049 60
2050 } else {
2051 40
2052 };
2053 let maintainability_score = if security_issues.is_empty() && !design_patterns.is_empty() {
2054 80
2055 } else {
2056 60
2057 };
2058 let overall_quality = (complexity_score + maintainability_score) as f32 / 2.0;
2059
2060 JavaAnalysisResult {
2061 oop_patterns,
2062 design_patterns,
2063 framework_usage,
2064 security_issues,
2065 performance_notes,
2066 modern_features,
2067 complexity_score,
2068 maintainability_score,
2069 overall_quality,
2070 }
2071 }
2072
2073 fn analyze_class_hierarchies(&self, content: &str) -> Result<Vec<ClassHierarchyInfo>> {
2075 let mut hierarchies = Vec::new();
2076
2077 let class_regex = Regex::new(
2079 r"(?m)^(?:\s*public\s+)?(?:abstract\s+)?class\s+(\w+)(?:\s+extends\s+(\w+))?(?:\s+implements\s+([\w\s,]+))?",
2080 )?;
2081
2082 for captures in class_regex.captures_iter(content) {
2083 let class_name = captures.get(1).unwrap().as_str().to_string();
2084 let superclass = captures.get(2).map(|m| m.as_str().to_string());
2085
2086 let interfaces = if let Some(interfaces_str) = captures.get(3) {
2087 interfaces_str
2088 .as_str()
2089 .split(',')
2090 .map(|s| s.trim().to_string())
2091 .collect()
2092 } else {
2093 Vec::new()
2094 };
2095
2096 let is_abstract = content.contains(&format!("abstract class {class_name}"));
2098 let is_final = content.contains(&format!("final class {class_name}"));
2099
2100 hierarchies.push(ClassHierarchyInfo {
2101 class_name: class_name.clone(),
2102 superclass,
2103 interfaces,
2104 subclasses: self.find_subclasses(content, &class_name),
2105 hierarchy_depth: self.calculate_hierarchy_depth(content, &class_name),
2106 is_abstract,
2107 is_final,
2108 modifiers: self.extract_class_modifiers(content, &class_name),
2109 });
2110 }
2111
2112 Ok(hierarchies)
2113 }
2114
2115 fn detect_design_patterns(&self, content: &str) -> Result<Vec<DesignPatternInfo>> {
2117 let mut patterns = Vec::new();
2118
2119 if content.contains("private static")
2121 && content.contains("getInstance")
2122 && content.contains("private")
2123 && content.contains("()")
2124 {
2125 patterns.push(DesignPatternInfo {
2126 pattern_type: DesignPatternType::Singleton,
2127 confidence: 0.8,
2128 implementation_quality: ImplementationQuality::Good,
2129 location: "Singleton class".to_string(),
2130 description: "Singleton pattern implementation detected".to_string(),
2131 participants: vec!["Singleton".to_string()],
2132 });
2133 }
2134
2135 if content.contains("Builder")
2137 && content.contains("build()")
2138 && content.contains("return this")
2139 {
2140 patterns.push(DesignPatternInfo {
2141 pattern_type: DesignPatternType::Builder,
2142 confidence: 0.9,
2143 implementation_quality: ImplementationQuality::Good,
2144 location: "Builder class".to_string(),
2145 description: "Builder pattern implementation detected".to_string(),
2146 participants: vec!["Builder".to_string()],
2147 });
2148 }
2149
2150 if content.contains("Factory") && content.contains("create") && content.contains("switch") {
2152 patterns.push(DesignPatternInfo {
2153 pattern_type: DesignPatternType::Factory,
2154 confidence: 0.7,
2155 implementation_quality: ImplementationQuality::Good,
2156 location: "Factory class".to_string(),
2157 description: "Factory pattern implementation detected".to_string(),
2158 participants: vec!["Factory".to_string()],
2159 });
2160 }
2161
2162 Ok(patterns)
2163 }
2164
2165 fn analyze_encapsulation(&self, content: &str) -> Result<Vec<EncapsulationInfo>> {
2167 let mut encapsulation_info = Vec::new();
2168
2169 let class_regex = Regex::new(r"(?m)^(?:\s*public\s+)?class\s+(\w+)")?;
2171
2172 for captures in class_regex.captures_iter(content) {
2173 let class_name = captures.get(1).unwrap().as_str().to_string();
2174
2175 let field_access_analysis = self.analyze_field_access(content, &class_name)?;
2177 let getter_setter_patterns = self.analyze_getter_setters(content, &class_name)?;
2178 let data_hiding_score = self.calculate_data_hiding_score(&field_access_analysis);
2179 let immutability_patterns = self.analyze_immutability_patterns(content, &class_name)?;
2180
2181 encapsulation_info.push(EncapsulationInfo {
2182 class_name,
2183 field_access_analysis,
2184 getter_setter_patterns,
2185 data_hiding_score,
2186 immutability_patterns,
2187 });
2188 }
2189
2190 Ok(encapsulation_info)
2191 }
2192
2193 fn analyze_polymorphism(&self, content: &str) -> Result<Vec<PolymorphismInfo>> {
2195 let mut polymorphism_usage = Vec::new();
2196
2197 let override_regex =
2199 Regex::new(r"@Override\s+(?:public\s+|protected\s+|private\s+)?(\w+)\s+(\w+)\s*\(")
2200 .unwrap();
2201
2202 for captures in override_regex.captures_iter(content) {
2203 let method_name = captures.get(2).unwrap().as_str().to_string();
2204 let overriding_class =
2205 self.find_containing_class(content, captures.get(0).unwrap().start());
2206
2207 if let Some(class_name) = overriding_class {
2208 polymorphism_usage.push(PolymorphismInfo {
2209 polymorphism_type: PolymorphismType::Inheritance,
2210 base_type: self
2211 .find_base_type(content, &class_name)
2212 .unwrap_or("Object".to_string()),
2213 derived_types: vec![class_name.clone()],
2214 method_overrides: vec![MethodOverrideInfo {
2215 method_name: method_name.clone(),
2216 overriding_class: class_name,
2217 base_class: "Unknown".to_string(), has_override_annotation: true,
2219 preserves_contract: true, changes_behavior: false, }],
2222 dynamic_dispatch_usage: true,
2223 });
2224 }
2225 }
2226
2227 Ok(polymorphism_usage)
2228 }
2229
2230 fn analyze_inheritance_patterns(&self, content: &str) -> Result<Vec<InheritancePatternInfo>> {
2232 let mut patterns = Vec::new();
2233
2234 let extends_regex = Regex::new(r"class\s+(\w+)\s+extends\s+(\w+)").unwrap();
2236
2237 for captures in extends_regex.captures_iter(content) {
2238 let derived_class = captures.get(1).unwrap().as_str().to_string();
2239 let base_class = captures.get(2).unwrap().as_str().to_string();
2240
2241 patterns.push(InheritancePatternInfo {
2242 pattern_type: InheritancePatternType::SingleInheritance,
2243 base_class: base_class.clone(),
2244 derived_classes: vec![derived_class],
2245 depth: self.calculate_inheritance_depth(content, &base_class),
2246 complexity_score: self.calculate_inheritance_complexity(content, &base_class),
2247 potential_issues: self.identify_inheritance_issues(content, &base_class),
2248 });
2249 }
2250
2251 Ok(patterns)
2252 }
2253
2254 fn analyze_interface_usage(&self, content: &str) -> Result<Vec<InterfaceUsageInfo>> {
2256 let mut interface_usage = Vec::new();
2257
2258 let interface_regex = Regex::new(r"interface\s+(\w+)").unwrap();
2260
2261 for captures in interface_regex.captures_iter(content) {
2262 let interface_name = captures.get(1).unwrap().as_str().to_string();
2263 let implementing_classes = self.find_implementing_classes(content, &interface_name);
2264 let methods = self.extract_interface_methods(content, &interface_name)?;
2265 let functional_interface = self.is_functional_interface(&methods);
2266 let lambda_usage = if functional_interface {
2267 self.find_lambda_usage(content, &interface_name)?
2268 } else {
2269 Vec::new()
2270 };
2271
2272 interface_usage.push(InterfaceUsageInfo {
2273 interface_name,
2274 implementing_classes,
2275 methods,
2276 functional_interface,
2277 lambda_usage,
2278 });
2279 }
2280
2281 Ok(interface_usage)
2282 }
2283
2284 fn evaluate_solid_principles(&self, content: &str) -> Result<SOLIDPrinciplesScore> {
2286 let single_responsibility = self.evaluate_srp(content);
2287 let open_closed = self.evaluate_ocp(content);
2288 let liskov_substitution = self.evaluate_lsp(content);
2289 let interface_segregation = self.evaluate_isp(content);
2290 let dependency_inversion = self.evaluate_dip(content);
2291
2292 let overall_score = (single_responsibility
2293 + open_closed
2294 + liskov_substitution
2295 + interface_segregation
2296 + dependency_inversion)
2297 / 5;
2298
2299 let violations = self.identify_solid_violations(content)?;
2300
2301 Ok(SOLIDPrinciplesScore {
2302 single_responsibility,
2303 open_closed,
2304 liskov_substitution,
2305 interface_segregation,
2306 dependency_inversion,
2307 overall_score,
2308 violations,
2309 })
2310 }
2311
2312 fn detect_frameworks(&self, content: &str) -> Result<Vec<FrameworkInfo>> {
2314 let mut frameworks = Vec::new();
2315
2316 for (framework_name, patterns) in &self.framework_patterns {
2317 let mut confidence = 0.0;
2318 let mut features_used = Vec::new();
2319 let mut total_weight = 0.0;
2320
2321 for pattern in patterns {
2322 if pattern.pattern.is_match(content) {
2323 confidence += pattern.confidence_weight;
2324 total_weight += 1.0;
2325 features_used.push(pattern.name.clone());
2326 }
2327 }
2328
2329 if confidence > 0.0 {
2330 frameworks.push(FrameworkInfo {
2331 name: framework_name.clone(),
2332 version: self.detect_framework_version(content, framework_name),
2333 confidence: confidence / total_weight,
2334 usage_patterns: features_used,
2335 best_practices_followed: self
2336 .evaluate_framework_best_practices(content, framework_name),
2337 potential_issues: self.identify_framework_issues(content, framework_name),
2338 });
2339 }
2340 }
2341
2342 Ok(frameworks)
2343 }
2344
2345 fn analyze_spring_framework(&self, content: &str) -> Result<Option<SpringAnalysis>> {
2347 if content.contains("@RestController")
2349 || content.contains("@Controller")
2350 || content.contains("@Service")
2351 || content.contains("@Repository")
2352 || content.contains("@Autowired")
2353 || content.contains("@Component")
2354 {
2355 let spring_analysis = SpringAnalysis {
2356 spring_boot_used: content.contains("@SpringBootApplication")
2357 || content.contains("SpringApplication"),
2358 components: self.analyze_spring_components(content)?,
2359 dependency_injection: self.analyze_dependency_injection(content)?,
2360 aop_usage: self.analyze_aop_patterns(content)?,
2361 transaction_management: self.analyze_transactions(content)?,
2362 security_configuration: self.analyze_spring_security(content)?,
2363 data_access_patterns: self.analyze_data_access(content)?,
2364 };
2365
2366 Ok(Some(spring_analysis))
2367 } else {
2368 Ok(None)
2369 }
2370 }
2371
2372 fn detect_vulnerabilities(&self, content: &str) -> Result<Vec<SecurityVulnerability>> {
2374 let mut vulnerabilities = Vec::new();
2375
2376 vulnerabilities.extend(self.detect_sql_injection(content));
2378
2379 vulnerabilities.extend(self.detect_command_injection(content));
2381
2382 vulnerabilities.extend(self.detect_path_traversal(content));
2384
2385 vulnerabilities.extend(self.detect_hardcoded_credentials(content));
2387
2388 vulnerabilities.extend(self.detect_weak_cryptography(content));
2390
2391 vulnerabilities.extend(self.detect_deserialization_attacks(content));
2393
2394 vulnerabilities.extend(self.detect_xxe_vulnerabilities(content));
2396
2397 vulnerabilities.extend(self.detect_ldap_injection(content));
2399
2400 vulnerabilities.extend(self.detect_insecure_randomness(content));
2402
2403 vulnerabilities.extend(self.detect_session_fixation(content));
2405
2406 vulnerabilities.extend(self.detect_unvalidated_redirects(content));
2408
2409 vulnerabilities.extend(self.detect_insecure_direct_object_references(content));
2411
2412 vulnerabilities.extend(self.detect_xss_vulnerabilities(content));
2414
2415 vulnerabilities.extend(self.detect_csrf_vulnerabilities(content));
2417
2418 Ok(vulnerabilities)
2419 }
2420
2421 fn detect_sql_injection(&self, content: &str) -> Vec<SecurityVulnerability> {
2423 let mut vulnerabilities = Vec::new();
2424
2425 let sql_concat_patterns = vec![
2427 r#""SELECT.*"\s*\+\s*\w+"#,
2428 r#""INSERT.*"\s*\+\s*\w+"#,
2429 r#""UPDATE.*"\s*\+\s*\w+"#,
2430 r#""DELETE.*"\s*\+\s*\w+"#,
2431 r#"String\.format\s*\(\s*".*SELECT.*%s.*""#,
2432 r#"MessageFormat\.format\s*\(\s*".*SELECT.*\{0\}.*""#,
2433 ];
2434
2435 for pattern in sql_concat_patterns {
2436 if let Ok(regex) = Regex::new(pattern) {
2437 if regex.is_match(content) {
2438 vulnerabilities.push(SecurityVulnerability {
2439 vulnerability_type: SecurityVulnerabilityType::SqlInjection,
2440 severity: SecuritySeverity::High,
2441 location: self.find_pattern_location(content, ®ex),
2442 description: "SQL injection vulnerability detected through string concatenation or formatting".to_string(),
2443 cwe_id: Some("CWE-89".to_string()),
2444 recommendation: "Use PreparedStatement, NamedParameterJdbcTemplate, or JPA with parameterized queries".to_string(),
2445 });
2446 }
2447 }
2448 }
2449
2450 if content.contains("createQuery(")
2452 && (content.contains("+ ") || content.contains("concat("))
2453 {
2454 vulnerabilities.push(SecurityVulnerability {
2455 vulnerability_type: SecurityVulnerabilityType::SqlInjection,
2456 severity: SecuritySeverity::Medium,
2457 location: "Dynamic query construction".to_string(),
2458 description: "Dynamic query construction detected without proper parameterization"
2459 .to_string(),
2460 cwe_id: Some("CWE-89".to_string()),
2461 recommendation: "Use JPA criteria API or properly parameterized queries"
2462 .to_string(),
2463 });
2464 }
2465
2466 vulnerabilities
2467 }
2468
2469 fn detect_command_injection(&self, content: &str) -> Vec<SecurityVulnerability> {
2471 let mut vulnerabilities = Vec::new();
2472
2473 let command_patterns = vec![
2474 r#"Runtime\.getRuntime\(\)\.exec\s*\([^)]*\+[^)]*\)"#,
2475 r#"ProcessBuilder\s*\([^)]*\+[^)]*\)"#,
2476 r#"new\s+ProcessBuilder\s*\([^)]*\+[^)]*\)"#,
2477 r#"Process\.exec\s*\([^)]*\+[^)]*\)"#,
2478 ];
2479
2480 for pattern in command_patterns {
2481 if let Ok(regex) = Regex::new(pattern) {
2482 if regex.is_match(content) {
2483 vulnerabilities.push(SecurityVulnerability {
2484 vulnerability_type: SecurityVulnerabilityType::CommandInjection,
2485 severity: SecuritySeverity::Critical,
2486 location: self.find_pattern_location(content, ®ex),
2487 description: "Command injection vulnerability detected in system command execution".to_string(),
2488 cwe_id: Some("CWE-78".to_string()),
2489 recommendation: "Validate and whitelist user input, use ProcessBuilder with separate arguments, avoid shell execution".to_string(),
2490 });
2491 }
2492 }
2493 }
2494
2495 vulnerabilities
2496 }
2497
2498 fn detect_path_traversal(&self, content: &str) -> Vec<SecurityVulnerability> {
2500 let mut vulnerabilities = Vec::new();
2501
2502 let path_patterns = vec![
2503 r#"new\s+File\s*\([^)]*\+[^)]*\)"#,
2504 r#"Files\.read\s*\([^)]*\+[^)]*\)"#,
2505 r#"FileInputStream\s*\([^)]*\+[^)]*\)"#,
2506 r#"FileOutputStream\s*\([^)]*\+[^)]*\)"#,
2507 r#"\.getResourceAsStream\s*\([^)]*\+[^)]*\)"#,
2508 ];
2509
2510 for pattern in path_patterns {
2511 if let Ok(regex) = Regex::new(pattern) {
2512 if regex.is_match(content) {
2513 vulnerabilities.push(SecurityVulnerability {
2514 vulnerability_type: SecurityVulnerabilityType::PathTraversal,
2515 severity: SecuritySeverity::High,
2516 location: self.find_pattern_location(content, ®ex),
2517 description: "Path traversal vulnerability detected in file operations".to_string(),
2518 cwe_id: Some("CWE-22".to_string()),
2519 recommendation: "Validate file paths, use Path.normalize(), implement whitelist of allowed directories".to_string(),
2520 });
2521 }
2522 }
2523 }
2524
2525 if content.contains("../") || content.contains("..\\") {
2527 vulnerabilities.push(SecurityVulnerability {
2528 vulnerability_type: SecurityVulnerabilityType::PathTraversal,
2529 severity: SecuritySeverity::Medium,
2530 location: "File path operations".to_string(),
2531 description: "Directory traversal sequences detected in code".to_string(),
2532 cwe_id: Some("CWE-22".to_string()),
2533 recommendation:
2534 "Remove or validate directory traversal sequences, use absolute paths"
2535 .to_string(),
2536 });
2537 }
2538
2539 vulnerabilities
2540 }
2541
2542 fn detect_hardcoded_credentials(&self, content: &str) -> Vec<SecurityVulnerability> {
2544 let mut vulnerabilities = Vec::new();
2545
2546 let credential_patterns = vec![
2547 r#"password\s*=\s*"[^"]+""#,
2548 r#"PASSWORD\s*=\s*"[^"]+""#,
2549 r#"secret\s*=\s*"[^"]+""#,
2550 r#"SECRET\s*=\s*"[^"]+""#,
2551 r#"api[_-]?key\s*=\s*"[^"]+""#,
2552 r#"private[_-]?key\s*=\s*"[^"]+""#,
2553 r#"token\s*=\s*"[^"]+""#,
2554 r#"\.password\(\s*"[^"]+"\s*\)"#,
2555 r#"getConnection\s*\([^,]*,\s*"[^"]*",\s*"[^"]+"\s*\)"#,
2556 ];
2557
2558 for pattern in credential_patterns {
2559 if let Ok(regex) = Regex::new(pattern) {
2560 if regex.is_match(content) {
2561 vulnerabilities.push(SecurityVulnerability {
2562 vulnerability_type: SecurityVulnerabilityType::HardcodedCredentials,
2563 severity: SecuritySeverity::Critical,
2564 location: self.find_pattern_location(content, ®ex),
2565 description: "Hardcoded credentials detected in source code".to_string(),
2566 cwe_id: Some("CWE-798".to_string()),
2567 recommendation: "Use environment variables, secure configuration files, or secret management systems".to_string(),
2568 });
2569 }
2570 }
2571 }
2572
2573 vulnerabilities
2574 }
2575
2576 fn detect_weak_cryptography(&self, content: &str) -> Vec<SecurityVulnerability> {
2578 let mut vulnerabilities = Vec::new();
2579
2580 let weak_algorithms = vec![
2581 ("MD5", "CWE-327", SecuritySeverity::High),
2582 ("SHA1", "CWE-327", SecuritySeverity::Medium),
2583 ("SHA-1", "CWE-327", SecuritySeverity::Medium),
2584 ("DES", "CWE-327", SecuritySeverity::Critical),
2585 ("3DES", "CWE-327", SecuritySeverity::High),
2586 ("RC4", "CWE-327", SecuritySeverity::Critical),
2587 ];
2588
2589 for (algorithm, cwe, severity) in weak_algorithms {
2590 if content.contains(algorithm)
2591 || content.contains(&format!("getInstance(\"{algorithm}\")"))
2592 {
2593 vulnerabilities.push(SecurityVulnerability {
2594 vulnerability_type: SecurityVulnerabilityType::WeakCryptography,
2595 severity,
2596 location: "Cryptographic operations".to_string(),
2597 description: format!("Use of weak cryptographic algorithm {algorithm} detected"),
2598 cwe_id: Some(cwe.to_string()),
2599 recommendation: "Use strong algorithms like AES-GCM, SHA-256, SHA-512, or bcrypt for password hashing".to_string(),
2600 });
2601 }
2602 }
2603
2604 if content.contains("keySize = 64") || content.contains("keySize = 128") {
2606 vulnerabilities.push(SecurityVulnerability {
2607 vulnerability_type: SecurityVulnerabilityType::WeakCryptography,
2608 severity: SecuritySeverity::Medium,
2609 location: "Key generation".to_string(),
2610 description: "Weak cryptographic key size detected".to_string(),
2611 cwe_id: Some("CWE-326".to_string()),
2612 recommendation:
2613 "Use minimum 256-bit keys for symmetric encryption, 2048-bit for RSA"
2614 .to_string(),
2615 });
2616 }
2617
2618 vulnerabilities
2619 }
2620
2621 fn detect_deserialization_attacks(&self, content: &str) -> Vec<SecurityVulnerability> {
2623 let mut vulnerabilities = Vec::new();
2624
2625 let deserialization_patterns = vec![
2626 r#"ObjectInputStream\s*\([^)]*\)"#,
2627 r#"\.readObject\s*\(\s*\)"#,
2628 r#"\.readUnshared\s*\(\s*\)"#,
2629 r#"XMLDecoder\s*\([^)]*\)"#,
2630 r#"@JsonTypeInfo"#,
2631 r#"enableDefaultTyping"#,
2632 ];
2633
2634 for pattern in deserialization_patterns {
2635 if let Ok(regex) = Regex::new(pattern) {
2636 if regex.is_match(content) {
2637 vulnerabilities.push(SecurityVulnerability {
2638 vulnerability_type: SecurityVulnerabilityType::DeserializationAttack,
2639 severity: SecuritySeverity::Critical,
2640 location: self.find_pattern_location(content, ®ex),
2641 description: "Insecure deserialization vulnerability detected".to_string(),
2642 cwe_id: Some("CWE-502".to_string()),
2643 recommendation: "Avoid deserializing untrusted data, use whitelisting, implement custom readObject methods with validation".to_string(),
2644 });
2645 }
2646 }
2647 }
2648
2649 vulnerabilities
2650 }
2651
2652 fn detect_xxe_vulnerabilities(&self, content: &str) -> Vec<SecurityVulnerability> {
2654 let mut vulnerabilities = Vec::new();
2655
2656 let xxe_patterns = vec![
2657 r#"DocumentBuilderFactory\.newInstance\s*\(\s*\)"#,
2658 r#"SAXParserFactory\.newInstance\s*\(\s*\)"#,
2659 r#"XMLInputFactory\.newInstance\s*\(\s*\)"#,
2660 r#"TransformerFactory\.newInstance\s*\(\s*\)"#,
2661 ];
2662
2663 for pattern in xxe_patterns {
2664 if let Ok(regex) = Regex::new(pattern) {
2665 if regex.is_match(content) && !content.contains("setFeature") {
2666 vulnerabilities.push(SecurityVulnerability {
2667 vulnerability_type: SecurityVulnerabilityType::XXEVulnerability,
2668 severity: SecuritySeverity::High,
2669 location: self.find_pattern_location(content, ®ex),
2670 description: "XML External Entity (XXE) vulnerability detected in XML parsing".to_string(),
2671 cwe_id: Some("CWE-611".to_string()),
2672 recommendation: "Disable external entity processing by setting XMLConstants.FEATURE_SECURE_PROCESSING".to_string(),
2673 });
2674 }
2675 }
2676 }
2677
2678 vulnerabilities
2679 }
2680
2681 fn detect_ldap_injection(&self, content: &str) -> Vec<SecurityVulnerability> {
2683 let mut vulnerabilities = Vec::new();
2684
2685 let ldap_patterns = vec![
2686 r#"new\s+SearchControls\s*\([^)]*\+[^)]*\)"#,
2687 r#"\.search\s*\([^)]*\+[^)]*\)"#,
2688 r#"LdapContext\.search\s*\([^)]*\+[^)]*\)"#,
2689 ];
2690
2691 for pattern in ldap_patterns {
2692 if let Ok(regex) = Regex::new(pattern) {
2693 if regex.is_match(content) {
2694 vulnerabilities.push(SecurityVulnerability {
2695 vulnerability_type: SecurityVulnerabilityType::LdapInjection,
2696 severity: SecuritySeverity::High,
2697 location: self.find_pattern_location(content, ®ex),
2698 description:
2699 "LDAP injection vulnerability detected in directory operations"
2700 .to_string(),
2701 cwe_id: Some("CWE-90".to_string()),
2702 recommendation:
2703 "Validate and escape LDAP query parameters, use parameterized queries"
2704 .to_string(),
2705 });
2706 }
2707 }
2708 }
2709
2710 vulnerabilities
2711 }
2712
2713 fn detect_insecure_randomness(&self, content: &str) -> Vec<SecurityVulnerability> {
2715 let mut vulnerabilities = Vec::new();
2716
2717 if content.contains("new Random()") || content.contains("Math.random()") {
2718 vulnerabilities.push(SecurityVulnerability {
2719 vulnerability_type: SecurityVulnerabilityType::InsecureRandomness,
2720 severity: SecuritySeverity::Medium,
2721 location: "Random number generation".to_string(),
2722 description:
2723 "Insecure random number generation detected for security-sensitive operations"
2724 .to_string(),
2725 cwe_id: Some("CWE-338".to_string()),
2726 recommendation: "Use SecureRandom for cryptographic operations and security tokens"
2727 .to_string(),
2728 });
2729 }
2730
2731 vulnerabilities
2732 }
2733
2734 fn detect_session_fixation(&self, content: &str) -> Vec<SecurityVulnerability> {
2736 let mut vulnerabilities = Vec::new();
2737
2738 if content.contains("request.getSession(true)") && !content.contains("invalidate()") {
2739 vulnerabilities.push(SecurityVulnerability {
2740 vulnerability_type: SecurityVulnerabilityType::SessionFixation,
2741 severity: SecuritySeverity::Medium,
2742 location: "Session management".to_string(),
2743 description: "Session fixation vulnerability detected - sessions not invalidated on authentication".to_string(),
2744 cwe_id: Some("CWE-384".to_string()),
2745 recommendation: "Invalidate existing sessions and create new ones after successful authentication".to_string(),
2746 });
2747 }
2748
2749 vulnerabilities
2750 }
2751
2752 fn detect_unvalidated_redirects(&self, content: &str) -> Vec<SecurityVulnerability> {
2754 let mut vulnerabilities = Vec::new();
2755
2756 let redirect_patterns = vec![
2757 r#"response\.sendRedirect\s*\([^)]*\+[^)]*\)"#,
2758 r#"ModelAndView\s*\([^)]*\+[^)]*\)"#,
2759 r#"redirect:\s*\+\s*\w+"#,
2760 ];
2761
2762 for pattern in redirect_patterns {
2763 if let Ok(regex) = Regex::new(pattern) {
2764 if regex.is_match(content) {
2765 vulnerabilities.push(SecurityVulnerability {
2766 vulnerability_type: SecurityVulnerabilityType::UnvalidatedRedirect,
2767 severity: SecuritySeverity::Medium,
2768 location: self.find_pattern_location(content, ®ex),
2769 description: "Unvalidated redirect vulnerability detected".to_string(),
2770 cwe_id: Some("CWE-601".to_string()),
2771 recommendation:
2772 "Validate redirect URLs against a whitelist of allowed destinations"
2773 .to_string(),
2774 });
2775 }
2776 }
2777 }
2778
2779 vulnerabilities
2780 }
2781
2782 fn detect_insecure_direct_object_references(
2784 &self,
2785 content: &str,
2786 ) -> Vec<SecurityVulnerability> {
2787 let mut vulnerabilities = Vec::new();
2788
2789 let idor_patterns = vec![
2791 r#"findById\s*\(\s*request\.getParameter\s*\([^)]*\)\s*\)"#,
2792 r#"findById\s*\(\s*@PathVariable[^)]*\)"#,
2793 r#"getById\s*\(\s*@RequestParam[^)]*\)"#,
2794 ];
2795
2796 for pattern in idor_patterns {
2797 if let Ok(regex) = Regex::new(pattern) {
2798 if regex.is_match(content)
2799 && !content.contains("@PreAuthorize")
2800 && !content.contains("hasPermission")
2801 {
2802 vulnerabilities.push(SecurityVulnerability {
2803 vulnerability_type: SecurityVulnerabilityType::InsecureDirectObjectReference,
2804 severity: SecuritySeverity::High,
2805 location: self.find_pattern_location(content, ®ex),
2806 description: "Insecure direct object reference detected - missing authorization checks".to_string(),
2807 cwe_id: Some("CWE-639".to_string()),
2808 recommendation: "Implement proper authorization checks before accessing objects, use @PreAuthorize or manual permission verification".to_string(),
2809 });
2810 }
2811 }
2812 }
2813
2814 vulnerabilities
2815 }
2816
2817 fn detect_xss_vulnerabilities(&self, content: &str) -> Vec<SecurityVulnerability> {
2819 let mut vulnerabilities = Vec::new();
2820
2821 if content.contains("@ResponseBody")
2823 && !content.contains("HtmlUtils.htmlEscape")
2824 && !content.contains("StringEscapeUtils")
2825 {
2826 vulnerabilities.push(SecurityVulnerability {
2827 vulnerability_type: SecurityVulnerabilityType::XssVulnerability,
2828 severity: SecuritySeverity::Medium,
2829 location: "Response body generation".to_string(),
2830 description: "Potential XSS vulnerability - unescaped output in response"
2831 .to_string(),
2832 cwe_id: Some("CWE-79".to_string()),
2833 recommendation:
2834 "Escape HTML output using HtmlUtils.htmlEscape or use proper templating engines"
2835 .to_string(),
2836 });
2837 }
2838
2839 vulnerabilities
2840 }
2841
2842 fn detect_csrf_vulnerabilities(&self, content: &str) -> Vec<SecurityVulnerability> {
2844 let mut vulnerabilities = Vec::new();
2845
2846 if content.contains("csrf().disable()") {
2847 vulnerabilities.push(SecurityVulnerability {
2848 vulnerability_type: SecurityVulnerabilityType::CsrfVulnerability,
2849 severity: SecuritySeverity::Medium,
2850 location: "Security configuration".to_string(),
2851 description: "CSRF protection disabled in security configuration".to_string(),
2852 cwe_id: Some("CWE-352".to_string()),
2853 recommendation: "Enable CSRF protection or implement custom CSRF token validation"
2854 .to_string(),
2855 });
2856 }
2857
2858 vulnerabilities
2859 }
2860
2861 fn analyze_lambda_expressions(&self, content: &str) -> Result<Vec<LambdaExpressionInfo>> {
2863 let mut lambdas = Vec::new();
2864
2865 let lambda_regex = Regex::new(r"(\([^)]*\)\s*->|[\w\s]*\s*->)").unwrap();
2866
2867 for m in lambda_regex.find_iter(content) {
2868 lambdas.push(LambdaExpressionInfo {
2869 expression: m.as_str().to_string(),
2870 functional_interface: self.infer_functional_interface(content, m.start()),
2871 complexity: self.assess_lambda_complexity(m.as_str()),
2872 captures_variables: self.checks_variable_capture(content, m.start(), m.end()),
2873 usage_context: self.get_lambda_context(content, m.start()),
2874 performance_impact: self.assess_lambda_performance_impact(m.as_str()),
2875 });
2876 }
2877
2878 Ok(lambdas)
2879 }
2880
2881 fn analyze_performance(&self, content: &str) -> Result<JavaPerformanceAnalysis> {
2883 let algorithm_complexity = self.analyze_algorithm_complexity(content)?;
2884 let collection_usage = self.analyze_collection_usage(content)?;
2885 let memory_patterns = self.analyze_memory_patterns(content)?;
2886 let concurrency_patterns = self.analyze_concurrency_patterns(content)?;
2887 let performance_issues = self.identify_performance_issues(content)?;
2888 let optimization_opportunities = self.identify_optimization_opportunities(content)?;
2889 let overall_performance_score = self.calculate_performance_score(
2890 &algorithm_complexity,
2891 &performance_issues,
2892 &optimization_opportunities,
2893 );
2894
2895 Ok(JavaPerformanceAnalysis {
2896 algorithm_complexity,
2897 collection_usage,
2898 memory_patterns,
2899 concurrency_patterns,
2900 performance_issues,
2901 optimization_opportunities,
2902 overall_performance_score,
2903 })
2904 }
2905
2906 fn find_subclasses(&self, content: &str, class_name: &str) -> Vec<String> {
2908 let regex = Regex::new(&format!(r"class\s+(\w+)\s+extends\s+{class_name}")).unwrap();
2909 regex
2910 .captures_iter(content)
2911 .filter_map(|cap| cap.get(1).map(|m| m.as_str().to_string()))
2912 .collect()
2913 }
2914
2915 fn calculate_hierarchy_depth(&self, content: &str, class_name: &str) -> usize {
2916 let mut depth = 0;
2917 let mut current_class = class_name.to_string();
2918 let mut visited = std::collections::HashSet::new();
2919
2920 while let Some(superclass) = self.find_superclass(content, ¤t_class) {
2921 if visited.contains(&superclass) {
2922 break; }
2924 visited.insert(superclass.clone());
2925 depth += 1;
2926 current_class = superclass;
2927 }
2928
2929 depth
2930 }
2931
2932 fn find_superclass(&self, content: &str, class_name: &str) -> Option<String> {
2933 let regex = Regex::new(&format!(r"class\s+{class_name}\s+extends\s+(\w+)")).unwrap();
2934 regex
2935 .captures(content)
2936 .and_then(|cap| cap.get(1).map(|m| m.as_str().to_string()))
2937 }
2938
2939 fn extract_class_modifiers(&self, content: &str, class_name: &str) -> Vec<String> {
2940 let regex = Regex::new(&format!(
2941 r"((?:public|private|protected|abstract|final|static)\s+)*class\s+{class_name}"
2942 ))
2943 .unwrap();
2944 regex
2945 .captures(content)
2946 .and_then(|cap| cap.get(1))
2947 .map(|m| m.as_str())
2948 .unwrap_or("")
2949 .split_whitespace()
2950 .filter(|s| !s.is_empty())
2951 .map(|s| s.to_string())
2952 .collect()
2953 }
2954
2955 fn assess_pattern_quality(&self, _content: &str, _pattern_type: &str) -> ImplementationQuality {
2956 ImplementationQuality::Good
2958 }
2959
2960 fn find_pattern_location(&self, content: &str, pattern: &Regex) -> String {
2961 pattern
2962 .find(content)
2963 .map(|m| format!("Line {}", self.get_line_number(content, m.start())))
2964 .unwrap_or_else(|| "Unknown".to_string())
2965 }
2966
2967 fn get_pattern_description(&self, pattern_type: &str) -> String {
2968 match pattern_type {
2969 "singleton" => "Singleton pattern ensures a class has only one instance".to_string(),
2970 "factory" => {
2971 "Factory pattern creates objects without specifying exact classes".to_string()
2972 }
2973 "builder" => "Builder pattern constructs complex objects step by step".to_string(),
2974 "observer" => {
2975 "Observer pattern defines one-to-many dependency between objects".to_string()
2976 }
2977 _ => format!("{pattern_type} pattern detected"),
2978 }
2979 }
2980
2981 fn identify_pattern_participants(&self, _content: &str, _pattern_type: &str) -> Vec<String> {
2982 Vec::new()
2984 }
2985
2986 fn get_line_number(&self, content: &str, position: usize) -> usize {
2987 content[..position].chars().filter(|&c| c == '\n').count() + 1
2988 }
2989
2990 fn assess_implementation_quality(
2994 &self,
2995 content: &str,
2996 pattern_type: &str,
2997 ) -> ImplementationQuality {
2998 match pattern_type {
2999 "sanitization" => {
3000 if content.contains("OWASP") || content.contains("AntiSamy") {
3001 ImplementationQuality::Excellent
3002 } else if content.contains("htmlEscape") || content.contains("StringEscapeUtils") {
3003 ImplementationQuality::Good
3004 } else {
3005 ImplementationQuality::Poor
3006 }
3007 }
3008 "authentication" => {
3009 if content.contains("@EnableWebSecurity")
3010 && content.contains("BCryptPasswordEncoder")
3011 {
3012 ImplementationQuality::Excellent
3013 } else if content.contains("@PreAuthorize") || content.contains("@Secured") {
3014 ImplementationQuality::Good
3015 } else {
3016 ImplementationQuality::Adequate
3017 }
3018 }
3019 _ => ImplementationQuality::Adequate,
3020 }
3021 }
3022
3023 fn analyze_jwt_weaknesses(&self, content: &str) -> Vec<String> {
3025 let mut weaknesses = Vec::new();
3026
3027 if content.contains("none") || content.contains("\"alg\": \"none\"") {
3028 weaknesses.push("JWT algorithm set to 'none' - vulnerable to tampering".to_string());
3029 }
3030
3031 if content.contains("HS256") && !content.contains("secret") {
3032 weaknesses.push("Weak JWT secret key management".to_string());
3033 }
3034
3035 if !content.contains("expiration") && !content.contains("exp") {
3036 weaknesses.push("JWT tokens without expiration time".to_string());
3037 }
3038
3039 weaknesses
3040 }
3041
3042 fn analyze_oauth2_weaknesses(&self, content: &str) -> Vec<String> {
3044 let mut weaknesses = Vec::new();
3045
3046 if content.contains("http://") && content.contains("redirectUri") {
3047 weaknesses.push("OAuth2 redirect URI using HTTP instead of HTTPS".to_string());
3048 }
3049
3050 if content.contains("client_secret") && content.contains("=") {
3051 weaknesses.push("Potential hardcoded OAuth2 client secret".to_string());
3052 }
3053
3054 weaknesses
3055 }
3056
3057 fn analyze_form_auth_weaknesses(&self, content: &str) -> Vec<String> {
3059 let mut weaknesses = Vec::new();
3060
3061 if !content.contains("BCryptPasswordEncoder") && !content.contains("SCryptPasswordEncoder")
3062 {
3063 weaknesses.push("Weak password encoding mechanism".to_string());
3064 }
3065
3066 if !content.contains("sessionManagement") {
3067 weaknesses.push("Missing session management configuration".to_string());
3068 }
3069
3070 weaknesses
3071 }
3072
3073 fn extract_roles_from_content(&self, content: &str) -> Vec<String> {
3075 let mut roles = Vec::new();
3076 let role_regex = Regex::new(r"ROLE_(\w+)").unwrap();
3077
3078 for captures in role_regex.captures_iter(content) {
3079 if let Some(role) = captures.get(1) {
3080 roles.push(format!("ROLE_{}", role.as_str()));
3081 }
3082 }
3083
3084 if roles.is_empty() {
3085 if content.contains("ADMIN") {
3087 roles.push("ROLE_ADMIN".to_string());
3088 }
3089 if content.contains("USER") {
3090 roles.push("ROLE_USER".to_string());
3091 }
3092 }
3093
3094 roles
3095 }
3096
3097 fn extract_permissions_from_content(&self, content: &str) -> Vec<String> {
3099 let mut permissions = Vec::new();
3100
3101 if content.contains("READ") {
3102 permissions.push("READ".to_string());
3103 }
3104 if content.contains("WRITE") {
3105 permissions.push("WRITE".to_string());
3106 }
3107 if content.contains("DELETE") {
3108 permissions.push("DELETE".to_string());
3109 }
3110 if content.contains("CREATE") {
3111 permissions.push("CREATE".to_string());
3112 }
3113
3114 permissions
3115 }
3116
3117 fn extract_access_control_rules(&self, content: &str) -> Vec<String> {
3119 let mut rules = Vec::new();
3120
3121 if content.contains("@PreAuthorize") {
3122 let pre_auth_regex = Regex::new(r#"@PreAuthorize\("([^"]+)"\)"#).unwrap();
3123 for captures in pre_auth_regex.captures_iter(content) {
3124 if let Some(rule) = captures.get(1) {
3125 rules.push(rule.as_str().to_string());
3126 }
3127 }
3128 }
3129
3130 if content.contains("@PostAuthorize") {
3131 let post_auth_regex = Regex::new(r#"@PostAuthorize\("([^"]+)"\)"#).unwrap();
3132 for captures in post_auth_regex.captures_iter(content) {
3133 if let Some(rule) = captures.get(1) {
3134 rules.push(rule.as_str().to_string());
3135 }
3136 }
3137 }
3138
3139 rules
3140 }
3141
3142 fn extract_sanitization_techniques(&self, content: &str) -> Vec<String> {
3144 let mut techniques = Vec::new();
3145
3146 if content.contains("htmlEscape") {
3147 techniques.push("HTML escaping".to_string());
3148 }
3149 if content.contains("StringEscapeUtils") {
3150 techniques.push("Apache Commons Text escaping".to_string());
3151 }
3152 if content.contains("OWASP") {
3153 techniques.push("OWASP sanitization library".to_string());
3154 }
3155 if content.contains("Jsoup.clean") {
3156 techniques.push("Jsoup HTML sanitization".to_string());
3157 }
3158
3159 techniques
3160 }
3161
3162 fn extract_crypto_algorithm(&self, content: &str, operation_type: &str) -> String {
3164 match operation_type {
3165 "encryption" => {
3166 if content.contains("AES") {
3167 if content.contains("AES/GCM/") {
3168 "AES-GCM".to_string()
3169 } else if content.contains("AES/CBC/") {
3170 "AES-CBC".to_string()
3171 } else {
3172 "AES".to_string()
3173 }
3174 } else if content.contains("RSA") {
3175 "RSA".to_string()
3176 } else {
3177 "Unknown".to_string()
3178 }
3179 }
3180 "hashing" => {
3181 if content.contains("SHA-256") || content.contains("SHA256") {
3182 "SHA-256".to_string()
3183 } else if content.contains("SHA-512") || content.contains("SHA512") {
3184 "SHA-512".to_string()
3185 } else if content.contains("SHA-1") || content.contains("SHA1") {
3186 "SHA-1".to_string()
3187 } else if content.contains("MD5") {
3188 "MD5".to_string()
3189 } else if content.contains("BCrypt") {
3190 "BCrypt".to_string()
3191 } else {
3192 "Unknown".to_string()
3193 }
3194 }
3195 _ => "Unknown".to_string(),
3196 }
3197 }
3198
3199 fn analyze_key_management(&self, content: &str) -> KeyManagementPattern {
3201 let key_storage = if content.contains("KeyStore") {
3202 KeyStorageType::Keystore
3203 } else if content.contains("HSM") {
3204 KeyStorageType::HSM
3205 } else if content.contains("System.getenv") || content.contains("@Value") {
3206 KeyStorageType::Environment
3207 } else if content.contains("\"key\"") || content.contains("password =") {
3208 KeyStorageType::Hardcoded
3209 } else {
3210 KeyStorageType::Configuration
3211 };
3212
3213 let key_strength = if content.contains("2048") || content.contains("256") {
3214 KeyStrength::Strong
3215 } else if content.contains("1024") || content.contains("128") {
3216 KeyStrength::Adequate
3217 } else if content.contains("512") || content.contains("64") {
3218 KeyStrength::Weak
3219 } else {
3220 KeyStrength::Unknown
3221 };
3222
3223 KeyManagementPattern {
3224 key_storage,
3225 key_rotation: content.contains("rotation") || content.contains("renew"),
3226 key_strength,
3227 key_derivation: if content.contains("PBKDF2") {
3228 Some("PBKDF2".to_string())
3229 } else if content.contains("scrypt") {
3230 Some("scrypt".to_string())
3231 } else {
3232 None
3233 },
3234 }
3235 }
3236
3237 fn identify_crypto_issues(&self, content: &str, algorithm: &str) -> Vec<String> {
3239 let mut issues = Vec::new();
3240
3241 match algorithm {
3242 "MD5" => {
3243 issues.push("MD5 is cryptographically broken and should not be used".to_string())
3244 }
3245 "SHA-1" => issues.push(
3246 "SHA-1 is deprecated and should be replaced with SHA-256 or better".to_string(),
3247 ),
3248 "AES-ECB" => issues.push("ECB mode is insecure and should not be used".to_string()),
3249 _ => {}
3250 }
3251
3252 if content.contains("new Random()") {
3253 issues.push(
3254 "Using weak random number generator for cryptographic operations".to_string(),
3255 );
3256 }
3257
3258 if content.contains("DES") {
3259 issues.push("DES encryption is weak and should be replaced with AES".to_string());
3260 }
3261
3262 issues
3263 }
3264
3265 fn extract_csrf_config(&self, content: &str) -> Vec<String> {
3267 let mut config = Vec::new();
3268
3269 if content.contains("csrf().disable()") {
3270 config.push("CSRF protection disabled".to_string());
3271 } else if content.contains("csrfTokenRepository") {
3272 config.push("Custom CSRF token repository configured".to_string());
3273 } else if content.contains("csrf()") {
3274 config.push("Default CSRF protection enabled".to_string());
3275 }
3276
3277 config
3278 }
3279
3280 fn extract_xss_config(&self, content: &str) -> Vec<String> {
3282 let mut config = Vec::new();
3283
3284 if content.contains("X-XSS-Protection") {
3285 config.push("XSS Protection header configured".to_string());
3286 }
3287 if content.contains("htmlEscape") {
3288 config.push("HTML output escaping implemented".to_string());
3289 }
3290 if content.contains("@ResponseBody") {
3291 config.push("Response body serialization (potential XSS vector)".to_string());
3292 }
3293
3294 config
3295 }
3296
3297 fn assess_xss_protection_effectiveness(&self, content: &str) -> SecurityEffectiveness {
3299 if content.contains("OWASP") || content.contains("AntiSamy") {
3300 SecurityEffectiveness::Excellent
3301 } else if content.contains("htmlEscape") || content.contains("StringEscapeUtils") {
3302 SecurityEffectiveness::Good
3303 } else if content.contains("@ResponseBody") && !content.contains("escape") {
3304 SecurityEffectiveness::Poor
3305 } else {
3306 SecurityEffectiveness::Adequate
3307 }
3308 }
3309
3310 fn extract_https_config(&self, content: &str) -> Vec<String> {
3312 let mut config = Vec::new();
3313
3314 if content.contains("requiresChannel().requestMatchers") {
3315 config.push("Channel security configured".to_string());
3316 }
3317 if content.contains("HTTPS") {
3318 config.push("HTTPS enforcement detected".to_string());
3319 }
3320 if content.contains("secure: true") {
3321 config.push("Secure cookie configuration".to_string());
3322 }
3323
3324 config
3325 }
3326
3327 fn extract_csp_config(&self, content: &str) -> Vec<String> {
3329 let mut config = Vec::new();
3330
3331 if content.contains("Content-Security-Policy") {
3332 config.push("Content Security Policy configured".to_string());
3333 }
3334 if content.contains("X-Frame-Options") {
3335 config.push("Frame options configured".to_string());
3336 }
3337 if content.contains("X-Content-Type-Options") {
3338 config.push("Content type options configured".to_string());
3339 }
3340
3341 config
3342 }
3343
3344 fn extract_cors_config(&self, content: &str) -> Vec<String> {
3346 let mut config = Vec::new();
3347
3348 if content.contains("@CrossOrigin") {
3349 config.push("Cross-origin annotations detected".to_string());
3350 }
3351 if content.contains("allowedOrigins") {
3352 config.push("Allowed origins configured".to_string());
3353 }
3354 if content.contains("allowCredentials") {
3355 config.push("Credentials allowed in CORS".to_string());
3356 }
3357
3358 config
3359 }
3360
3361 fn assess_cors_security(&self, content: &str) -> SecurityEffectiveness {
3363 if content.contains("allowedOrigins(\"*\")") || content.contains("origins = \"*\"") {
3364 SecurityEffectiveness::Poor
3365 } else if content.contains("allowedOrigins") && content.contains("https://") {
3366 SecurityEffectiveness::Good
3367 } else if content.contains("@CrossOrigin") && !content.contains("origins") {
3368 SecurityEffectiveness::Adequate
3369 } else {
3370 SecurityEffectiveness::Good
3371 }
3372 }
3373
3374 fn calculate_overall_score(&self, content: &str) -> i32 {
3375 let oop_score = self.calculate_oop_score_safe(content);
3380 let framework_score = self.calculate_framework_score_safe(content);
3381 let security_score = self.calculate_security_score_safe(content);
3382 let modernity_score = self.calculate_modernity_score(content);
3383 let performance_score = 75; let weighted_score = (oop_score as f32 * 0.25) + (framework_score as f32 * 0.20) + (security_score as f32 * 0.25) + (modernity_score as f32 * 0.15) + (performance_score as f32 * 0.15); weighted_score.round().max(0.0).min(100.0) as i32
3394 }
3395
3396 fn calculate_oop_score_safe(&self, content: &str) -> i32 {
3398 match self.evaluate_solid_principles(content) {
3399 Ok(solid_score) => solid_score.overall_score,
3400 Err(_) => {
3401 let mut score = 60; if content.contains("private") {
3406 score += 10;
3407 }
3408 if content.contains("public") && content.contains("private") {
3409 score += 5;
3410 }
3411 if content.contains("final") {
3412 score += 5;
3413 }
3414 if content.contains("interface") {
3415 score += 10;
3416 }
3417 if content.contains("extends") {
3418 score += 5;
3419 }
3420 if content.contains("@Override") {
3421 score += 5;
3422 }
3423
3424 if content.contains("public static") {
3426 score -= 5;
3427 }
3428 if content.matches("public").count() > content.matches("private").count() * 2 {
3429 score -= 10;
3430 }
3431
3432 score.max(0).min(100)
3433 }
3434 }
3435 }
3436
3437 fn calculate_framework_score_safe(&self, content: &str) -> i32 {
3439 let mut score = 50; if content.contains("@Autowired") {
3443 score += 10;
3444 }
3445 if content.contains("@Service") || content.contains("@Repository") {
3446 score += 10;
3447 }
3448 if content.contains("@RestController") || content.contains("@Controller") {
3449 score += 10;
3450 }
3451 if content.contains("@Component") {
3452 score += 5;
3453 }
3454 if content.contains("@PreAuthorize") {
3455 score += 10;
3456 }
3457
3458 if content.contains("@Test") {
3460 score += 10;
3461 }
3462 if content.contains("assertThat") || content.contains("assertEquals") {
3463 score += 5;
3464 }
3465
3466 score.max(0).min(100)
3467 }
3468
3469 fn calculate_security_score_safe(&self, content: &str) -> i32 {
3471 let mut score = 70; if content.contains("@PreAuthorize") {
3475 score += 10;
3476 }
3477 if content.contains("@Secured") {
3478 score += 5;
3479 }
3480 if content.contains("BCrypt") || content.contains("PasswordEncoder") {
3481 score += 10;
3482 }
3483 if content.contains("HTTPS") || content.contains("SecurityConfig") {
3484 score += 5;
3485 }
3486
3487 if content.contains("SQLException") && content.contains("executeQuery") {
3489 score -= 15;
3490 }
3491 if content.contains("Runtime.getRuntime().exec") {
3492 score -= 20;
3493 }
3494 if content.contains("new File(") && content.contains("request.getParameter") {
3495 score -= 15;
3496 }
3497 if content.contains("password") && content.contains("\"") {
3498 score -= 10;
3499 } score.max(0).min(100)
3502 }
3503
3504 fn generate_recommendations(&self, _content: &str) -> Vec<String> {
3505 vec![
3506 "Consider using more modern Java features like Streams and Optional".to_string(),
3507 "Implement proper error handling and logging".to_string(),
3508 "Review security patterns and input validation".to_string(),
3509 "Consider applying SOLID principles more consistently".to_string(),
3510 ]
3511 }
3512
3513 fn analyze_field_access(
3518 &self,
3519 content: &str,
3520 class_name: &str,
3521 ) -> Result<Vec<FieldAccessInfo>> {
3522 let mut field_access_info = Vec::new();
3523
3524 let class_content = self.extract_class_content(content, class_name);
3526
3527 let field_regex = Regex::new(
3529 r"(?m)^\s*(public|protected|private|)\s*(static\s+)?(final\s+)?(\w+(?:<[^>]+>)?)\s+(\w+)\s*[=;]",
3530 )?;
3531
3532 for captures in field_regex.captures_iter(&class_content) {
3533 let access_modifier = match captures.get(1).map(|m| m.as_str().trim()) {
3534 Some("public") => AccessModifier::Public,
3535 Some("protected") => AccessModifier::Protected,
3536 Some("private") => AccessModifier::Private,
3537 _ => AccessModifier::PackagePrivate,
3538 };
3539
3540 let is_static = captures.get(2).is_some();
3541 let is_final = captures.get(3).is_some();
3542 let field_type = captures.get(4).unwrap().as_str().to_string();
3543 let field_name = captures.get(5).unwrap().as_str().to_string();
3544
3545 let proper_encapsulation = match access_modifier {
3547 AccessModifier::Private => {
3548 let getter_pattern = format!(r"(?i)get{field_name}");
3550 let setter_pattern = format!(r"(?i)set{field_name}");
3551 let has_getter = Regex::new(&getter_pattern)
3552 .unwrap()
3553 .is_match(&class_content);
3554 let has_setter = Regex::new(&setter_pattern)
3555 .unwrap()
3556 .is_match(&class_content);
3557 has_getter || has_setter || is_final
3558 }
3559 AccessModifier::Public => false, _ => true, };
3562
3563 field_access_info.push(FieldAccessInfo {
3564 field_name,
3565 access_modifier,
3566 is_final,
3567 is_static,
3568 field_type,
3569 proper_encapsulation,
3570 });
3571 }
3572
3573 Ok(field_access_info)
3574 }
3575
3576 fn analyze_getter_setters(
3577 &self,
3578 content: &str,
3579 class_name: &str,
3580 ) -> Result<Vec<GetterSetterInfo>> {
3581 let mut getter_setter_info = Vec::new();
3582 let class_content = self.extract_class_content(content, class_name);
3583
3584 let field_regex = Regex::new(
3586 r"(?m)^\s*(?:public|protected|private|)\s*(?:static\s+)?(?:final\s+)?\w+(?:<[^>]+>)?\s+(\w+)\s*[=;]",
3587 )?;
3588 let fields: Vec<String> = field_regex
3589 .captures_iter(&class_content)
3590 .map(|cap| cap.get(1).unwrap().as_str().to_string())
3591 .collect();
3592
3593 for field_name in fields {
3594 let getter_name = format!(
3596 "get{}",
3597 field_name
3598 .chars()
3599 .next()
3600 .unwrap()
3601 .to_uppercase()
3602 .chain(field_name.chars().skip(1))
3603 .collect::<String>()
3604 );
3605 let getter_pattern = format!(
3606 r"(?m)^\s*(?:public|protected)\s+\w+(?:<[^>]+>)?\s+{getter_name}\s*\(\s*\)"
3607 );
3608 let has_getter = Regex::new(&getter_pattern)
3609 .unwrap()
3610 .is_match(&class_content);
3611
3612 let setter_name = format!(
3614 "set{}",
3615 field_name
3616 .chars()
3617 .next()
3618 .unwrap()
3619 .to_uppercase()
3620 .chain(field_name.chars().skip(1))
3621 .collect::<String>()
3622 );
3623 let setter_pattern = format!(
3624 r"(?m)^\s*(?:public|protected)\s+(?:void|{class_name})\s+{setter_name}\s*\([^)]+\)"
3625 );
3626 let has_setter = Regex::new(&setter_pattern)
3627 .unwrap()
3628 .is_match(&class_content);
3629
3630 let follows_naming_convention =
3632 getter_name.starts_with("get") && setter_name.starts_with("set");
3633
3634 let validation_in_setter = if has_setter {
3636 let setter_content_pattern = format!(
3637 r"(?s){setter_name}[^{{]*\{{[^}}]*(?:if|throw|validate|check|assert)[^}}]*\}}"
3638 );
3639 Regex::new(&setter_content_pattern)
3640 .unwrap()
3641 .is_match(&class_content)
3642 } else {
3643 false
3644 };
3645
3646 if has_getter || has_setter {
3647 getter_setter_info.push(GetterSetterInfo {
3648 field_name,
3649 has_getter,
3650 has_setter,
3651 getter_name,
3652 setter_name,
3653 follows_naming_convention,
3654 validation_in_setter,
3655 });
3656 }
3657 }
3658
3659 Ok(getter_setter_info)
3660 }
3661
3662 fn calculate_data_hiding_score(&self, field_access_analysis: &[FieldAccessInfo]) -> i32 {
3663 if field_access_analysis.is_empty() {
3664 return 50; }
3666
3667 let total_fields = field_access_analysis.len() as i32;
3668 let properly_encapsulated = field_access_analysis
3669 .iter()
3670 .filter(|field| field.proper_encapsulation)
3671 .count() as i32;
3672 let private_fields = field_access_analysis
3673 .iter()
3674 .filter(|field| matches!(field.access_modifier, AccessModifier::Private))
3675 .count() as i32;
3676 let public_fields = field_access_analysis
3677 .iter()
3678 .filter(|field| matches!(field.access_modifier, AccessModifier::Public))
3679 .count() as i32;
3680
3681 let encapsulation_score = (properly_encapsulated * 100) / total_fields;
3683 let access_modifier_score =
3684 ((private_fields * 2 + (total_fields - public_fields - private_fields)) * 100)
3685 / (total_fields * 2);
3686
3687 (encapsulation_score * 60 + access_modifier_score * 40) / 100
3689 }
3690
3691 fn analyze_immutability_patterns(
3692 &self,
3693 content: &str,
3694 class_name: &str,
3695 ) -> Result<Vec<ImmutabilityPattern>> {
3696 let mut immutability_patterns = Vec::new();
3697 let class_content = self.extract_class_content(content, class_name);
3698
3699 let is_final_class = class_content.contains(&format!("final class {class_name}"));
3701
3702 let field_regex = Regex::new(
3704 r"(?m)^\s*(?:public|protected|private|)\s*(?:static\s+)?(final\s+)?(\w+(?:<[^>]+>)?)\s+(\w+)\s*[=;]",
3705 )?;
3706
3707 let mut immutable_fields = Vec::new();
3708 let mut mutable_fields = Vec::new();
3709
3710 for captures in field_regex.captures_iter(&class_content) {
3711 let is_final = captures.get(1).is_some();
3712 let field_type = captures.get(2).unwrap().as_str();
3713 let field_name = captures.get(3).unwrap().as_str().to_string();
3714
3715 let is_immutable_type = matches!(
3717 field_type,
3718 "String"
3719 | "int"
3720 | "long"
3721 | "double"
3722 | "float"
3723 | "boolean"
3724 | "char"
3725 | "byte"
3726 | "short"
3727 | "Integer"
3728 | "Long"
3729 | "Double"
3730 | "Float"
3731 | "Boolean"
3732 | "Character"
3733 | "Byte"
3734 | "Short"
3735 | "BigInteger"
3736 | "BigDecimal"
3737 | "LocalDate"
3738 | "LocalDateTime"
3739 | "Instant"
3740 ) || field_type.starts_with("Immutable");
3741
3742 if is_final && is_immutable_type {
3743 immutable_fields.push(field_name);
3744 } else {
3745 mutable_fields.push(field_name);
3746 }
3747 }
3748
3749 let total_fields = immutable_fields.len() + mutable_fields.len();
3751 let immutability_level = if total_fields == 0 {
3752 ImmutabilityLevel::FullyImmutable
3753 } else {
3754 let immutable_ratio = immutable_fields.len() as f32 / total_fields as f32;
3755 match immutable_ratio {
3756 1.0 => ImmutabilityLevel::FullyImmutable,
3757 r if r >= 0.8 => ImmutabilityLevel::MostlyImmutable,
3758 r if r >= 0.5 => ImmutabilityLevel::PartiallyImmutable,
3759 _ => ImmutabilityLevel::Mutable,
3760 }
3761 };
3762
3763 let builder_pattern_used = class_content.contains("builder()")
3765 || class_content.contains("Builder")
3766 || class_content.contains("build()");
3767
3768 immutability_patterns.push(ImmutabilityPattern {
3769 class_name: class_name.to_string(),
3770 immutability_level,
3771 immutable_fields,
3772 builder_pattern_used,
3773 });
3774
3775 Ok(immutability_patterns)
3776 }
3777
3778 fn find_containing_class(&self, content: &str, position: usize) -> Option<String> {
3779 let before_position = &content[..position];
3780 let class_regex = Regex::new(r"class\s+(\w+)").unwrap();
3781
3782 class_regex
3784 .captures_iter(before_position)
3785 .last()
3786 .and_then(|cap| cap.get(1).map(|m| m.as_str().to_string()))
3787 }
3788
3789 fn find_base_type(&self, content: &str, class_name: &str) -> Option<String> {
3790 self.find_superclass(content, class_name)
3791 }
3792
3793 fn calculate_inheritance_depth(&self, _content: &str, _base_class: &str) -> usize {
3794 1
3795 }
3796
3797 fn calculate_inheritance_complexity(&self, _content: &str, _base_class: &str) -> i32 {
3798 50
3799 }
3800
3801 fn identify_inheritance_issues(&self, _content: &str, _base_class: &str) -> Vec<String> {
3802 Vec::new()
3803 }
3804
3805 fn find_implementing_classes(&self, content: &str, interface_name: &str) -> Vec<String> {
3806 let regex = Regex::new(&format!(r"class\s+(\w+).*implements.*{interface_name}")).unwrap();
3807 regex
3808 .captures_iter(content)
3809 .filter_map(|cap| cap.get(1).map(|m| m.as_str().to_string()))
3810 .collect()
3811 }
3812
3813 fn extract_interface_methods(
3814 &self,
3815 content: &str,
3816 interface_name: &str,
3817 ) -> Result<Vec<InterfaceMethodInfo>> {
3818 let mut methods = Vec::new();
3819
3820 let interface_pattern = [
3822 "interface\\s+",
3823 interface_name,
3824 "\\s*(?:\\w+\\s+)*\\{([^}]+)\\}",
3825 ]
3826 .concat();
3827 let interface_regex = Regex::new(&interface_pattern)?;
3828
3829 if let Some(captures) = interface_regex.captures(content) {
3830 let interface_body = captures.get(1).unwrap().as_str();
3831
3832 let method_regex = Regex::new(
3834 r"(?:default\s+|static\s+)?([\w<>\[\]]+)\s+(\w+)\s*\(([^)]*)\)(?:\s*\{[^}]*\})?;",
3835 )?;
3836
3837 for captures in method_regex.captures_iter(interface_body) {
3838 let return_type = captures.get(1).unwrap().as_str().to_string();
3839 let method_name = captures.get(2).unwrap().as_str().to_string();
3840 let params_str = captures.get(3).unwrap().as_str();
3841
3842 let method_line = captures.get(0).unwrap().as_str();
3844 let is_default = method_line.contains("default ");
3845 let is_static = method_line.contains("static ");
3846
3847 let parameters = if params_str.trim().is_empty() {
3849 Vec::new()
3850 } else {
3851 params_str
3852 .split(',')
3853 .map(|param| param.trim().to_string())
3854 .collect()
3855 };
3856
3857 methods.push(InterfaceMethodInfo {
3858 method_name,
3859 is_default,
3860 is_static,
3861 parameters,
3862 return_type,
3863 });
3864 }
3865 }
3866
3867 Ok(methods)
3868 }
3869
3870 fn is_functional_interface(&self, methods: &[InterfaceMethodInfo]) -> bool {
3871 methods
3872 .iter()
3873 .filter(|m| !m.is_default && !m.is_static)
3874 .count()
3875 == 1
3876 }
3877
3878 fn find_lambda_usage(
3879 &self,
3880 content: &str,
3881 interface_name: &str,
3882 ) -> Result<Vec<LambdaUsageInfo>> {
3883 let mut lambda_usages = Vec::new();
3884
3885 let lambda_patterns = [
3887 r"(\w+)::\w+",
3889 r"\([^)]*\)\s*->\s*[^;]+",
3891 r"\w+\s*->\s*[^;]+",
3892 ];
3893
3894 for pattern in &lambda_patterns {
3895 let regex = Regex::new(pattern)?;
3896 for m in regex.find_iter(content) {
3897 let lambda_text = m.as_str();
3898
3899 let lambda_type = if lambda_text.contains("::") {
3901 LambdaType::MethodReference
3902 } else if lambda_text.contains("{") {
3903 LambdaType::Statement
3904 } else {
3905 LambdaType::Expression
3906 };
3907
3908 let complexity = if lambda_text.len() < 20 {
3910 LambdaComplexity::Simple
3911 } else if lambda_text.len() < 50 {
3912 LambdaComplexity::Moderate
3913 } else {
3914 LambdaComplexity::Complex
3915 };
3916
3917 let captures_variables = lambda_text.contains("final")
3919 || self.has_external_variable_references(content, m.start(), m.end());
3920
3921 let context = self.extract_usage_context(content, m.start());
3922
3923 lambda_usages.push(LambdaUsageInfo {
3924 usage_context: context,
3925 lambda_type,
3926 complexity,
3927 captures_variables,
3928 });
3929 }
3930 }
3931
3932 Ok(lambda_usages)
3933 }
3934
3935 fn evaluate_srp(&self, content: &str) -> i32 {
3936 let class_regex = Regex::new(r"class\s+(\w+)").unwrap();
3938 let mut total_score = 0;
3939 let mut class_count = 0;
3940
3941 for captures in class_regex.captures_iter(content) {
3942 let class_name = captures.get(1).unwrap().as_str();
3943 let class_content = self.extract_class_content(content, class_name);
3944
3945 let method_regex =
3947 Regex::new(r"(?:public|protected|private)\s+(?:\w+\s+)?(\w+)\s+(\w+)\s*\(")
3948 .unwrap();
3949 let methods: Vec<_> = method_regex.captures_iter(&class_content).collect();
3950
3951 let has_crud = methods.iter().any(|cap| {
3953 let method_name = cap.get(2).unwrap().as_str();
3954 method_name.starts_with("save")
3955 || method_name.starts_with("delete")
3956 || method_name.starts_with("create")
3957 || method_name.starts_with("update")
3958 });
3959 let has_validation = methods.iter().any(|cap| {
3960 let method_name = cap.get(2).unwrap().as_str();
3961 method_name.contains("validate") || method_name.contains("check")
3962 });
3963 let has_calculation = methods.iter().any(|cap| {
3964 let method_name = cap.get(2).unwrap().as_str();
3965 method_name.contains("calculate") || method_name.contains("compute")
3966 });
3967 let has_formatting = methods.iter().any(|cap| {
3968 let method_name = cap.get(2).unwrap().as_str();
3969 method_name.contains("format") || method_name.contains("toString")
3970 });
3971
3972 let responsibility_count = [has_crud, has_validation, has_calculation, has_formatting]
3974 .iter()
3975 .filter(|&&x| x)
3976 .count();
3977 let class_score = match responsibility_count {
3978 0..=1 => 90,
3979 2 => 70,
3980 3 => 50,
3981 _ => 30,
3982 };
3983
3984 total_score += class_score;
3985 class_count += 1;
3986 }
3987
3988 if class_count > 0 {
3989 total_score / class_count
3990 } else {
3991 70
3992 }
3993 }
3994
3995 fn evaluate_ocp(&self, content: &str) -> i32 {
3996 let mut score = 50; if content.contains("interface ") && content.contains("implements ") {
4001 score += 20;
4002 }
4003
4004 if content.contains("abstract class ") {
4006 score += 15;
4007 }
4008
4009 if content.contains("Strategy") || content.contains("Policy") || content.contains("Handler")
4011 {
4012 score += 15;
4013 }
4014
4015 let switch_pattern = Regex::new(r"switch\s*\([^)]+\)\s*\{").unwrap();
4018 let switch_count = switch_pattern.find_iter(content).count();
4019 if switch_count > 2 {
4020 score -= (switch_count as i32 - 2) * 5;
4021 }
4022
4023 score.min(100).max(0)
4024 }
4025
4026 fn evaluate_lsp(&self, content: &str) -> i32 {
4027 let mut score = 70; let override_pattern = Regex::new(r"@Override\s+(?:public|protected|private)\s+").unwrap();
4032 let override_count = override_pattern.find_iter(content).count();
4033 let method_count = Regex::new(r"(?:public|protected)\s+\w+\s+\w+\s*\(")
4034 .unwrap()
4035 .find_iter(content)
4036 .count();
4037
4038 if method_count > 0 {
4039 let override_ratio = override_count as f32 / method_count as f32;
4040 if override_ratio > 0.5 {
4041 score += 15; }
4043 }
4044
4045 if content.contains("super.") {
4047 score += 10;
4048 }
4049
4050 if content.contains("@Override") && content.contains("throw new") {
4052 score -= 20;
4053 }
4054
4055 score.min(100).max(0)
4056 }
4057
4058 fn evaluate_isp(&self, content: &str) -> i32 {
4059 let interface_regex = Regex::new(r"interface\s+(\w+)\s*\{([^}]+)\}").unwrap();
4061 let mut total_score = 0;
4062 let mut interface_count = 0;
4063
4064 for captures in interface_regex.captures_iter(content) {
4065 let interface_content = captures.get(2).unwrap().as_str();
4066 let method_pattern = Regex::new(r"\w+\s+\w+\s*\([^)]*\)\s*;").unwrap();
4068 let method_count = method_pattern.find_iter(interface_content).count();
4069
4070 let interface_score = match method_count {
4072 1..=3 => 90, 4..=6 => 75, 7..=10 => 60, _ => 40, };
4077
4078 total_score += interface_score;
4079 interface_count += 1;
4080 }
4081
4082 if interface_count > 0 {
4083 total_score / interface_count
4084 } else {
4085 70
4086 }
4087 }
4088
4089 fn evaluate_dip(&self, content: &str) -> i32 {
4090 let mut score = 50; if content.contains("@Autowired") || content.contains("@Inject") {
4095 score += 20;
4096 }
4097
4098 if content.contains("@Autowired") && content.matches("public.*\\(.*\\)").count() > 0 {
4100 score += 15;
4101 }
4102
4103 let interface_dependencies = Regex::new(r"@Autowired\s+(\w+)")
4105 .unwrap()
4106 .captures_iter(content)
4107 .filter(|cap| {
4108 let dep_type = cap.get(1).unwrap().as_str();
4109 dep_type.ends_with("Service")
4110 || dep_type.ends_with("Repository")
4111 || dep_type.ends_with("Interface")
4112 || dep_type.chars().next().unwrap().is_uppercase()
4113 })
4114 .count();
4115
4116 if interface_dependencies > 0 {
4117 score += 15;
4118 }
4119
4120 let new_pattern = Regex::new(r"\bnew\s+\w+\s*\(").unwrap();
4122 let new_count = new_pattern.find_iter(content).count();
4123 if new_count > 3 {
4124 score -= (new_count as i32 - 3) * 3;
4126 }
4127
4128 score.min(100).max(0)
4129 }
4130
4131 fn identify_solid_violations(&self, content: &str) -> Result<Vec<SOLIDViolation>> {
4132 let mut violations = Vec::new();
4133
4134 let class_regex = Regex::new(r"class\s+(\w+)")?;
4136 for captures in class_regex.captures_iter(content) {
4137 let class_name = captures.get(1).unwrap().as_str().to_string();
4138 let class_content = self.extract_class_content(content, &class_name);
4139
4140 let crud_methods = ["save", "delete", "create", "update", "insert"];
4142 let validation_methods = ["validate", "check", "verify"];
4143 let calculation_methods = ["calculate", "compute", "process"];
4144 let formatting_methods = ["format", "toString", "display"];
4145
4146 let has_crud = crud_methods
4147 .iter()
4148 .any(|&method| class_content.contains(method));
4149 let has_validation = validation_methods
4150 .iter()
4151 .any(|&method| class_content.contains(method));
4152 let has_calculation = calculation_methods
4153 .iter()
4154 .any(|&method| class_content.contains(method));
4155 let has_formatting = formatting_methods
4156 .iter()
4157 .any(|&method| class_content.contains(method));
4158
4159 let responsibility_count = [has_crud, has_validation, has_calculation, has_formatting]
4160 .iter()
4161 .filter(|&&x| x)
4162 .count();
4163
4164 if responsibility_count > 2 {
4165 violations.push(SOLIDViolation {
4166 principle: SOLIDPrinciple::SingleResponsibility,
4167 class_name: class_name.clone(),
4168 description: format!(
4169 "Class {class_name} has {responsibility_count} different types of responsibilities"
4170 ),
4171 severity: if responsibility_count > 3 {
4172 ViolationSeverity::High
4173 } else {
4174 ViolationSeverity::Medium
4175 },
4176 recommendation:
4177 "Consider splitting this class into smaller, more focused classes"
4178 .to_string(),
4179 });
4180 }
4181 }
4182
4183 let switch_regex = Regex::new(r"switch\s*\([^)]+\)\s*\{([^}]+)\}")?;
4185 for captures in switch_regex.captures_iter(content) {
4186 let switch_content = captures.get(1).unwrap().as_str();
4187 let case_pattern = Regex::new(r"case\s+[^:]+:").unwrap();
4189 let case_count = case_pattern.find_iter(switch_content).count();
4190
4191 if case_count > 5 {
4192 violations.push(SOLIDViolation {
4193 principle: SOLIDPrinciple::OpenClosed,
4194 class_name: "Switch statement".to_string(),
4195 description: format!("Large switch statement with {case_count} cases"),
4196 severity: ViolationSeverity::Medium,
4197 recommendation: "Consider using polymorphism or strategy pattern instead"
4198 .to_string(),
4199 });
4200 }
4201 }
4202
4203 let interface_regex = Regex::new(r"interface\s+(\w+)\s*\{([^}]+)\}")?;
4205 for captures in interface_regex.captures_iter(content) {
4206 let interface_name = captures.get(1).unwrap().as_str().to_string();
4207 let interface_content = captures.get(2).unwrap().as_str();
4208 let method_pattern = Regex::new(r"\w+\s+\w+\s*\([^)]*\)\s*;").unwrap();
4210 let method_count = method_pattern.find_iter(interface_content).count();
4211
4212 if method_count > 7 {
4213 violations.push(SOLIDViolation {
4214 principle: SOLIDPrinciple::InterfaceSegregation,
4215 class_name: interface_name.clone(),
4216 description: format!(
4217 "Interface {interface_name} has {method_count} methods, which is too many"
4218 ),
4219 severity: if method_count > 10 {
4220 ViolationSeverity::High
4221 } else {
4222 ViolationSeverity::Medium
4223 },
4224 recommendation:
4225 "Consider splitting this interface into smaller, more focused interfaces"
4226 .to_string(),
4227 });
4228 }
4229 }
4230
4231 let new_regex = Regex::new(r"new\s+([A-Z]\w+)\s*\(")?;
4233 let mut new_violations = std::collections::HashMap::new();
4234
4235 for captures in new_regex.captures_iter(content) {
4236 let class_name = captures.get(1).unwrap().as_str().to_string();
4237 if ![
4239 "String",
4240 "Integer",
4241 "Long",
4242 "Double",
4243 "Float",
4244 "Boolean",
4245 "ArrayList",
4246 "HashMap",
4247 "HashSet",
4248 ]
4249 .contains(&class_name.as_str())
4250 {
4251 *new_violations.entry(class_name).or_insert(0) += 1;
4252 }
4253 }
4254
4255 for (class_name, count) in new_violations {
4256 if count > 2 {
4257 violations.push(SOLIDViolation {
4258 principle: SOLIDPrinciple::DependencyInversion,
4259 class_name: class_name.clone(),
4260 description: format!(
4261 "Direct instantiation of {class_name} appears {count} times"
4262 ),
4263 severity: ViolationSeverity::Medium,
4264 recommendation:
4265 "Consider using dependency injection instead of direct instantiation"
4266 .to_string(),
4267 });
4268 }
4269 }
4270
4271 Ok(violations)
4272 }
4273
4274 fn detect_framework_version(&self, _content: &str, _framework_name: &str) -> Option<String> {
4275 None
4276 }
4277
4278 fn evaluate_framework_best_practices(
4279 &self,
4280 _content: &str,
4281 _framework_name: &str,
4282 ) -> Vec<String> {
4283 Vec::new()
4284 }
4285
4286 fn identify_framework_issues(&self, _content: &str, _framework_name: &str) -> Vec<String> {
4287 Vec::new()
4288 }
4289
4290 fn calculate_framework_score(&self, _frameworks: &[FrameworkInfo]) -> i32 {
4291 75
4292 }
4293
4294 fn analyze_spring_components(&self, content: &str) -> Result<Vec<SpringComponentInfo>> {
4295 let mut components = Vec::new();
4296
4297 let component_patterns = [
4299 ("@Component", SpringComponentType::Component),
4300 ("@Service", SpringComponentType::Service),
4301 ("@Repository", SpringComponentType::Repository),
4302 ("@Controller", SpringComponentType::Controller),
4303 ("@RestController", SpringComponentType::RestController),
4304 ("@Configuration", SpringComponentType::Configuration),
4305 ];
4306
4307 for (annotation, component_type) in component_patterns {
4308 let annotation_regex = Regex::new(&format!(
4310 r"{annotation}(?:\([^)]*\))?\s+(?:public\s+)?class\s+(\w+)"
4311 ))?;
4312
4313 for captures in annotation_regex.captures_iter(content) {
4314 let class_name = captures.get(1).unwrap().as_str().to_string();
4315
4316 let annotations = self.extract_class_annotations(content, &class_name);
4318
4319 let dependencies = self.find_autowired_dependencies(content, &class_name);
4321
4322 let scope = self.extract_component_scope(content, &class_name);
4324
4325 components.push(SpringComponentInfo {
4326 component_type: component_type.clone(),
4327 class_name,
4328 annotations,
4329 scope,
4330 dependencies,
4331 });
4332 }
4333 }
4334
4335 Ok(components)
4336 }
4337
4338 fn analyze_dependency_injection(&self, content: &str) -> Result<Vec<DIPatternInfo>> {
4339 let mut di_patterns = Vec::new();
4340
4341 let autowired_regex = Regex::new(
4343 r"@Autowired\s+(?:private\s+|protected\s+|public\s+)?(\w+(?:<[^>]+>)?)\s+(\w+)",
4344 )?;
4345
4346 for captures in autowired_regex.captures_iter(content) {
4347 let dependency_type = captures.get(1).unwrap().as_str().to_string();
4348 let field_name = captures.get(2).unwrap().as_str().to_string();
4349
4350 let class_name = self
4352 .find_containing_class(content, captures.get(0).unwrap().start())
4353 .unwrap_or_else(|| "Unknown".to_string());
4354
4355 let follows_best_practices = self.assess_di_best_practices(content, &field_name);
4357 let potential_issues = self.identify_di_issues(content, &field_name, &dependency_type);
4358
4359 di_patterns.push(DIPatternInfo {
4360 injection_type: DIType::Field,
4361 target_class: class_name,
4362 dependencies: vec![dependency_type],
4363 follows_best_practices,
4364 potential_issues,
4365 });
4366 }
4367
4368 let constructor_injection_regex = Regex::new(r"public\s+(\w+)\s*\(\s*([^)]+)\s*\)")?;
4370
4371 for captures in constructor_injection_regex.captures_iter(content) {
4372 let class_name = captures.get(1).unwrap().as_str().to_string();
4373 let params_str = captures.get(2).unwrap().as_str();
4374
4375 let is_di_constructor = content.contains("@Autowired")
4377 || self.count_constructors(content, &class_name) == 1;
4378
4379 if is_di_constructor {
4380 let dependencies = self.parse_constructor_parameters(params_str);
4381 let follows_best_practices = dependencies.len() <= 3; let potential_issues = if dependencies.len() > 5 {
4383 vec!["Too many dependencies - consider refactoring".to_string()]
4384 } else {
4385 Vec::new()
4386 };
4387
4388 di_patterns.push(DIPatternInfo {
4389 injection_type: DIType::Constructor,
4390 target_class: class_name,
4391 dependencies,
4392 follows_best_practices,
4393 potential_issues,
4394 });
4395 }
4396 }
4397
4398 Ok(di_patterns)
4399 }
4400
4401 fn extract_class_annotations(&self, content: &str, class_name: &str) -> Vec<String> {
4403 let mut annotations = Vec::new();
4404
4405 let class_regex = Regex::new(&format!(
4407 r"((?:@\w+(?:\([^)]*\))?\s*)*)\s*(?:public\s+)?class\s+{class_name}"
4408 ))
4409 .unwrap();
4410
4411 if let Some(captures) = class_regex.captures(content) {
4412 let annotations_text = captures.get(1).unwrap().as_str();
4413 let annotation_regex = Regex::new(r"@(\w+)(?:\([^)]*\))?").unwrap();
4414
4415 for annotation_capture in annotation_regex.captures_iter(annotations_text) {
4416 annotations.push(annotation_capture.get(0).unwrap().as_str().to_string());
4417 }
4418 }
4419
4420 annotations
4421 }
4422
4423 fn find_autowired_dependencies(&self, content: &str, class_name: &str) -> Vec<String> {
4424 let mut dependencies = Vec::new();
4425
4426 let class_start = content.find(&format!("class {class_name}"));
4428 if class_start.is_none() {
4429 return dependencies;
4430 }
4431
4432 let class_content = self.extract_class_content(content, class_name);
4433
4434 let autowired_regex = Regex::new(
4436 r"@Autowired\s+(?:private\s+|protected\s+|public\s+)?(\w+(?:<[^>]+>)?)\s+(\w+)",
4437 )
4438 .unwrap();
4439
4440 for captures in autowired_regex.captures_iter(&class_content) {
4441 let dependency_type = captures.get(1).unwrap().as_str();
4442 dependencies.push(dependency_type.to_string());
4443 }
4444
4445 dependencies
4446 }
4447
4448 fn extract_component_scope(&self, content: &str, class_name: &str) -> String {
4449 let scope_regex = Regex::new(&format!(
4451 r#"@Scope\s*\(\s*["']([^"']+)["']\s*\).*?class\s+{class_name}"#
4452 ))
4453 .unwrap();
4454
4455 if let Some(captures) = scope_regex.captures(content) {
4456 captures.get(1).unwrap().as_str().to_string()
4457 } else {
4458 "singleton".to_string() }
4460 }
4461
4462 fn extract_class_content(&self, content: &str, class_name: &str) -> String {
4463 let class_regex = Regex::new(&format!(
4465 r"class\s+{class_name}\s*\{{([^{{}}]*(?:\{{[^{{}}]*\}}[^{{}}]*)*)\}}"
4466 ))
4467 .unwrap();
4468
4469 if let Some(captures) = class_regex.captures(content) {
4470 captures.get(1).unwrap().as_str().to_string()
4471 } else {
4472 String::new()
4473 }
4474 }
4475
4476 fn assess_di_best_practices(&self, content: &str, field_name: &str) -> bool {
4477 let field_regex =
4479 Regex::new(&format!(r"(?:private\s+)?(?:final\s+)?\w+\s+{field_name}")).unwrap();
4480
4481 if let Some(field_match) = field_regex.find(content) {
4482 let field_def = field_match.as_str();
4483 field_def.contains("private") && !field_def.contains("public")
4484 } else {
4485 false
4486 }
4487 }
4488
4489 fn identify_di_issues(
4490 &self,
4491 content: &str,
4492 field_name: &str,
4493 dependency_type: &str,
4494 ) -> Vec<String> {
4495 let mut issues = Vec::new();
4496
4497 if content.contains("@Autowired")
4499 && dependency_type.contains("Service")
4500 && content.contains(&format!("class {field_name}Service"))
4501 {
4502 issues.push("Potential circular dependency detected".to_string());
4503 }
4504
4505 if content.contains("@Autowired") && content.contains(field_name) {
4507 issues.push(
4508 "Consider using constructor injection instead of field injection".to_string(),
4509 );
4510 }
4511
4512 issues
4513 }
4514
4515 fn count_constructors(&self, content: &str, class_name: &str) -> usize {
4516 let constructor_regex = Regex::new(&format!(r"public\s+{class_name}\s*\(")).unwrap();
4517 constructor_regex.find_iter(content).count()
4518 }
4519
4520 fn parse_constructor_parameters(&self, params_str: &str) -> Vec<String> {
4521 if params_str.trim().is_empty() {
4522 return Vec::new();
4523 }
4524
4525 params_str
4526 .split(',')
4527 .map(|param| {
4528 let parts: Vec<&str> = param.split_whitespace().collect();
4530 if parts.len() >= 2 {
4531 parts[0].to_string()
4532 } else {
4533 param.trim().to_string()
4534 }
4535 })
4536 .collect()
4537 }
4538
4539 fn analyze_aop_patterns(&self, content: &str) -> Result<Vec<AOPPatternInfo>> {
4540 let mut aop_patterns = Vec::new();
4541
4542 let aspect_regex = Regex::new(r"@Aspect\s+(?:public\s+)?class\s+(\w+)").unwrap();
4544
4545 for captures in aspect_regex.captures_iter(content) {
4546 let aspect_class = captures.get(1).unwrap().as_str().to_string();
4547
4548 let pointcuts = self.extract_pointcuts(content, &aspect_class);
4550 let advice_types = self.extract_advice_types(content, &aspect_class);
4551 let cross_cutting_concerns =
4552 self.identify_cross_cutting_concerns(content, &aspect_class);
4553
4554 aop_patterns.push(AOPPatternInfo {
4555 aspect_class,
4556 pointcuts,
4557 advice_types,
4558 cross_cutting_concerns,
4559 });
4560 }
4561
4562 Ok(aop_patterns)
4563 }
4564
4565 fn analyze_transactions(&self, content: &str) -> Result<Vec<TransactionInfo>> {
4566 let mut transactions = Vec::new();
4567
4568 let transactional_regex =
4570 Regex::new(r"@Transactional(?:\([^)]*\))?\s+(?:public\s+)?[\w<>\[\]]+\s+(\w+)\s*\(")
4571 .unwrap();
4572
4573 for captures in transactional_regex.captures_iter(content) {
4574 let method_name = captures.get(1).unwrap().as_str().to_string();
4575 let class_name = self
4576 .find_containing_class(content, captures.get(0).unwrap().start())
4577 .unwrap_or_else(|| "Unknown".to_string());
4578
4579 let annotation = captures.get(0).unwrap().as_str();
4581 let propagation = self
4582 .extract_transaction_attribute(annotation, "propagation")
4583 .unwrap_or_else(|| "REQUIRED".to_string());
4584 let isolation = self
4585 .extract_transaction_attribute(annotation, "isolation")
4586 .unwrap_or_else(|| "DEFAULT".to_string());
4587 let rollback_rules = self.extract_rollback_rules(annotation);
4588
4589 transactions.push(TransactionInfo {
4590 class_name,
4591 method_name,
4592 transaction_type: TransactionType::Declarative,
4593 propagation,
4594 isolation,
4595 rollback_rules,
4596 });
4597 }
4598
4599 if content.contains("TransactionTemplate") || content.contains("PlatformTransactionManager")
4601 {
4602 let class_regex = Regex::new(r"(?:public\s+)?class\s+(\w+)").unwrap();
4603
4604 for captures in class_regex.captures_iter(content) {
4605 let class_name = captures.get(1).unwrap().as_str().to_string();
4606 let class_content = self.extract_class_content(content, &class_name);
4607
4608 if class_content.contains("TransactionTemplate") {
4609 transactions.push(TransactionInfo {
4610 class_name: class_name.clone(),
4611 method_name: "programmaticTransaction".to_string(),
4612 transaction_type: TransactionType::Programmatic,
4613 propagation: "REQUIRED".to_string(),
4614 isolation: "DEFAULT".to_string(),
4615 rollback_rules: Vec::new(),
4616 });
4617 }
4618 }
4619 }
4620
4621 Ok(transactions)
4622 }
4623
4624 fn analyze_spring_security(&self, content: &str) -> Result<Option<SpringSecurityInfo>> {
4625 if !content.contains("@EnableWebSecurity")
4626 && !content.contains("WebSecurityConfigurerAdapter")
4627 && !content.contains("SecurityFilterChain")
4628 {
4629 return Ok(None);
4630 }
4631
4632 let authentication_mechanisms = self.extract_authentication_mechanisms(content);
4633 let authorization_patterns = self.extract_authorization_patterns(content);
4634 let security_configurations = self.extract_security_configurations(content);
4635 let csrf_protection = content.contains("csrf()") && !content.contains("csrf().disable()");
4636 let session_management = self.extract_session_management(content);
4637
4638 Ok(Some(SpringSecurityInfo {
4639 authentication_mechanisms,
4640 authorization_patterns,
4641 security_configurations,
4642 csrf_protection,
4643 session_management,
4644 }))
4645 }
4646
4647 fn analyze_data_access(&self, content: &str) -> Result<Vec<DataAccessPatternInfo>> {
4648 let mut data_access_patterns = Vec::new();
4649
4650 let jpa_repo_regex = Regex::new(r"interface\s+(\w+)\s+extends\s+(JpaRepository|CrudRepository|PagingAndSortingRepository)<([^>]+)>").unwrap();
4652
4653 for captures in jpa_repo_regex.captures_iter(content) {
4654 let implementation_class = captures.get(1).unwrap().as_str().to_string();
4655 let repo_type = captures.get(2).unwrap().as_str();
4656
4657 let pattern_type = match repo_type {
4658 "JpaRepository" => DataAccessPattern::JpaRepository,
4659 "CrudRepository" => DataAccessPattern::CrudRepository,
4660 _ => DataAccessPattern::JpaRepository,
4661 };
4662
4663 let database_operations =
4664 self.extract_database_operations(content, &implementation_class);
4665 let query_methods = self.extract_query_methods(content, &implementation_class)?;
4666
4667 data_access_patterns.push(DataAccessPatternInfo {
4668 pattern_type,
4669 implementation_class,
4670 database_operations,
4671 query_methods,
4672 });
4673 }
4674
4675 if content.contains("JdbcTemplate") {
4677 let class_regex = Regex::new(r"(?:public\s+)?class\s+(\w+)").unwrap();
4678
4679 for captures in class_regex.captures_iter(content) {
4680 let class_name = captures.get(1).unwrap().as_str().to_string();
4681 let class_content = self.extract_class_content(content, &class_name);
4682
4683 if class_content.contains("JdbcTemplate") {
4684 let pattern_type = if class_content.contains("NamedParameterJdbcTemplate") {
4685 DataAccessPattern::NamedParameterJdbcTemplate
4686 } else {
4687 DataAccessPattern::JdbcTemplate
4688 };
4689
4690 let database_operations = self.extract_jdbc_operations(content, &class_name);
4691
4692 data_access_patterns.push(DataAccessPatternInfo {
4693 pattern_type,
4694 implementation_class: class_name,
4695 database_operations,
4696 query_methods: Vec::new(),
4697 });
4698 }
4699 }
4700 }
4701
4702 Ok(data_access_patterns)
4703 }
4704
4705 fn analyze_hibernate(&self, content: &str) -> Result<Option<HibernateAnalysis>> {
4706 if !content.contains("@Entity")
4708 && !content.contains("javax.persistence")
4709 && !content.contains("jakarta.persistence")
4710 && !content.contains("hibernate")
4711 {
4712 return Ok(None);
4713 }
4714
4715 let entities = self.analyze_jpa_entities(content)?;
4716 let relationships = self.analyze_entity_relationships(content)?;
4717 let query_analysis = self.analyze_jpa_queries(content)?;
4718 let performance_considerations = self.identify_jpa_performance_issues(content)?;
4719 let configuration_analysis = self.analyze_jpa_configuration(content)?;
4720
4721 Ok(Some(HibernateAnalysis {
4722 entities,
4723 relationships,
4724 query_analysis,
4725 performance_considerations,
4726 configuration_analysis,
4727 }))
4728 }
4729
4730 fn analyze_junit(&self, content: &str) -> Result<Option<JUnitAnalysis>> {
4731 if !content.contains("org.junit")
4733 && !content.contains("@Test")
4734 && !content.contains("@BeforeEach")
4735 && !content.contains("@AfterEach")
4736 {
4737 return Ok(None);
4738 }
4739
4740 let junit_version =
4742 if content.contains("org.junit.jupiter") || content.contains("@BeforeEach") {
4743 JUnitVersion::JUnit5
4744 } else if content.contains("org.junit.Test")
4745 || content.contains("@Before") && content.contains("@After")
4746 {
4747 JUnitVersion::JUnit4
4748 } else if content.contains("org.junit") {
4749 JUnitVersion::Mixed
4750 } else {
4751 JUnitVersion::Unknown
4752 };
4753
4754 let test_classes = self.extract_test_classes(content)?;
4756
4757 let test_patterns = self.analyze_test_patterns(content);
4759
4760 let mocking_frameworks = self.detect_mocking_frameworks(content);
4762
4763 let coverage_patterns = self.analyze_coverage_patterns(content);
4765
4766 let best_practices_score = self.calculate_junit_best_practices_score(content);
4768
4769 Ok(Some(JUnitAnalysis {
4770 junit_version,
4771 test_classes,
4772 test_patterns,
4773 mocking_frameworks,
4774 coverage_patterns,
4775 best_practices_score,
4776 }))
4777 }
4778
4779 fn analyze_maven(&self, content: &str) -> Result<Option<MavenAnalysis>> {
4780 if !content.contains("maven")
4782 && !content.contains("<groupId>")
4783 && !content.contains("pom.xml")
4784 {
4785 return Ok(None);
4786 }
4787
4788 let project_info = MavenProjectInfo {
4790 group_id: "com.example".to_string(), artifact_id: "example-project".to_string(),
4792 version: "1.0.0".to_string(),
4793 packaging: "jar".to_string(),
4794 java_version: Some("11".to_string()),
4795 properties: vec!["maven.compiler.source=11".to_string()],
4796 };
4797
4798 let dependencies = self.extract_maven_dependencies_from_imports(content);
4800
4801 let plugins = Vec::new();
4803 let profiles = Vec::new();
4804 let dependency_management = Vec::new();
4805 let potential_issues = Vec::new();
4806
4807 Ok(Some(MavenAnalysis {
4808 project_info,
4809 dependencies,
4810 plugins,
4811 profiles,
4812 dependency_management,
4813 potential_issues,
4814 }))
4815 }
4816
4817 fn analyze_gradle(&self, content: &str) -> Result<Option<GradleAnalysis>> {
4818 if !content.contains("gradle")
4820 && !content.contains("implementation")
4821 && !content.contains("build.gradle")
4822 {
4823 return Ok(None);
4824 }
4825
4826 let project_info = GradleProjectInfo {
4827 project_name: "example-project".to_string(),
4828 version: "1.0.0".to_string(),
4829 java_version: Some("11".to_string()),
4830 gradle_version: Some("7.0".to_string()),
4831 source_compatibility: Some("11".to_string()),
4832 target_compatibility: Some("11".to_string()),
4833 };
4834
4835 let dependencies = self.extract_gradle_dependencies_from_imports(content);
4837
4838 let plugins = Vec::new();
4839 let tasks = Vec::new();
4840 let build_configurations = Vec::new();
4841 let potential_issues = Vec::new();
4842
4843 Ok(Some(GradleAnalysis {
4844 project_info,
4845 dependencies,
4846 plugins,
4847 tasks,
4848 build_configurations,
4849 potential_issues,
4850 }))
4851 }
4852
4853 fn detect_security_patterns(&self, content: &str) -> Result<Vec<SecurityPattern>> {
4855 let mut security_patterns = Vec::new();
4856
4857 if content.contains("StringEscapeUtils")
4859 || content.contains("OWASP")
4860 || content.contains("htmlEscape")
4861 || content.contains("sanitize")
4862 {
4863 security_patterns.push(SecurityPattern {
4864 pattern_type: SecurityPatternType::InputSanitization,
4865 implementation_quality: self.assess_implementation_quality(content, "sanitization"),
4866 location: "Multiple locations".to_string(),
4867 description: "Input sanitization implementation detected".to_string(),
4868 });
4869 }
4870
4871 if content.contains("@PreAuthorize")
4873 || content.contains("@Secured")
4874 || content.contains("SecurityContextHolder")
4875 || content.contains("UserDetails")
4876 {
4877 security_patterns.push(SecurityPattern {
4878 pattern_type: SecurityPatternType::SecureAuthentication,
4879 implementation_quality: self
4880 .assess_implementation_quality(content, "authentication"),
4881 location: "Authentication mechanisms".to_string(),
4882 description: "Authentication security patterns detected".to_string(),
4883 });
4884 }
4885
4886 if content.contains("@Audit")
4888 || content.contains("SecurityEvent")
4889 || content.contains("logger.info") && content.contains("security")
4890 {
4891 security_patterns.push(SecurityPattern {
4892 pattern_type: SecurityPatternType::AuditLogging,
4893 implementation_quality: self.assess_implementation_quality(content, "logging"),
4894 location: "Logging statements".to_string(),
4895 description: "Security audit logging detected".to_string(),
4896 });
4897 }
4898
4899 if content.contains("https://")
4901 || content.contains("TLS")
4902 || content.contains("SSLContext")
4903 || content.contains("HttpsURLConnection")
4904 {
4905 security_patterns.push(SecurityPattern {
4906 pattern_type: SecurityPatternType::SecureCommunication,
4907 implementation_quality: self
4908 .assess_implementation_quality(content, "communication"),
4909 location: "Network communication".to_string(),
4910 description: "Secure communication patterns detected".to_string(),
4911 });
4912 }
4913
4914 if content.contains("HttpSession")
4916 || content.contains("sessionManagement")
4917 || content.contains("invalidate()")
4918 || content.contains("JSESSIONID")
4919 {
4920 security_patterns.push(SecurityPattern {
4921 pattern_type: SecurityPatternType::SessionManagement,
4922 implementation_quality: self.assess_implementation_quality(content, "session"),
4923 location: "Session handling".to_string(),
4924 description: "Session management security patterns detected".to_string(),
4925 });
4926 }
4927
4928 Ok(security_patterns)
4929 }
4930
4931 fn analyze_authentication(&self, content: &str) -> Result<Vec<AuthenticationPattern>> {
4933 let mut auth_patterns = Vec::new();
4934
4935 if content.contains("JWT")
4937 || content.contains("JsonWebToken")
4938 || content.contains("jwtDecode")
4939 || content.contains("Claims")
4940 {
4941 let weaknesses = self.analyze_jwt_weaknesses(content);
4942 auth_patterns.push(AuthenticationPattern {
4943 authentication_type: AuthenticationType::JwtToken,
4944 implementation_class: "JWT Token Handler".to_string(),
4945 security_features: vec![
4946 "Token-based authentication".to_string(),
4947 "Stateless authentication".to_string(),
4948 ],
4949 weaknesses,
4950 });
4951 }
4952
4953 if content.contains("OAuth2")
4955 || content.contains("@EnableOAuth2Sso")
4956 || content.contains("OAuth2Authentication")
4957 || content.contains("AuthorizationServer")
4958 {
4959 let weaknesses = self.analyze_oauth2_weaknesses(content);
4960 auth_patterns.push(AuthenticationPattern {
4961 authentication_type: AuthenticationType::OAuth2,
4962 implementation_class: "OAuth2 Provider".to_string(),
4963 security_features: vec![
4964 "OAuth2 authorization flow".to_string(),
4965 "Token-based access control".to_string(),
4966 ],
4967 weaknesses,
4968 });
4969 }
4970
4971 if content.contains("formLogin")
4973 || content.contains("UsernamePasswordAuthenticationToken")
4974 || content.contains("AuthenticationProvider")
4975 {
4976 let weaknesses = self.analyze_form_auth_weaknesses(content);
4977 auth_patterns.push(AuthenticationPattern {
4978 authentication_type: AuthenticationType::FormBased,
4979 implementation_class: "Form Authentication".to_string(),
4980 security_features: vec![
4981 "Username/password authentication".to_string(),
4982 "Session-based authentication".to_string(),
4983 ],
4984 weaknesses,
4985 });
4986 }
4987
4988 if content.contains("BasicAuthenticationFilter")
4990 || content.contains("httpBasic")
4991 || content.contains("Authorization: Basic")
4992 {
4993 auth_patterns.push(AuthenticationPattern {
4994 authentication_type: AuthenticationType::BasicAuth,
4995 implementation_class: "Basic Authentication".to_string(),
4996 security_features: vec!["HTTP Basic authentication".to_string()],
4997 weaknesses: vec![
4998 "Credentials transmitted in base64 encoding".to_string(),
4999 "Vulnerable without HTTPS".to_string(),
5000 ],
5001 });
5002 }
5003
5004 Ok(auth_patterns)
5005 }
5006
5007 fn analyze_authorization(&self, content: &str) -> Result<Vec<AuthorizationPattern>> {
5009 let mut auth_patterns = Vec::new();
5010
5011 if content.contains("@RolesAllowed")
5013 || content.contains("hasRole")
5014 || content.contains("ROLE_")
5015 || content.contains("GrantedAuthority")
5016 {
5017 let roles = self.extract_roles_from_content(content);
5018 auth_patterns.push(AuthorizationPattern {
5019 authorization_type: AuthorizationType::RoleBased,
5020 roles,
5021 permissions: Vec::new(),
5022 access_control_rules: self.extract_access_control_rules(content),
5023 });
5024 }
5025
5026 if content.contains("@PreAuthorize")
5028 || content.contains("hasPermission")
5029 || content.contains("Permission")
5030 || content.contains("ACL")
5031 {
5032 let permissions = self.extract_permissions_from_content(content);
5033 auth_patterns.push(AuthorizationPattern {
5034 authorization_type: AuthorizationType::PermissionBased,
5035 roles: Vec::new(),
5036 permissions,
5037 access_control_rules: self.extract_access_control_rules(content),
5038 });
5039 }
5040
5041 if content.contains("@PostAuthorize")
5043 || content.contains("SecurityEvaluationContext")
5044 || content.contains("SpEL") && content.contains("security")
5045 {
5046 auth_patterns.push(AuthorizationPattern {
5047 authorization_type: AuthorizationType::AttributeBased,
5048 roles: Vec::new(),
5049 permissions: Vec::new(),
5050 access_control_rules: vec![
5051 "Attribute-based access control with SpEL expressions".to_string()
5052 ],
5053 });
5054 }
5055
5056 Ok(auth_patterns)
5057 }
5058
5059 fn analyze_input_validation(&self, content: &str) -> Result<Vec<InputValidationPattern>> {
5061 let mut validation_patterns = Vec::new();
5062
5063 if content.contains("@Valid")
5065 || content.contains("@NotNull")
5066 || content.contains("@Size")
5067 || content.contains("@Pattern")
5068 {
5069 validation_patterns.push(InputValidationPattern {
5070 validation_type: ValidationType::TypeValidation,
5071 input_sources: vec!["HTTP parameters".to_string(), "Request body".to_string()],
5072 validation_methods: vec!["Bean Validation annotations".to_string()],
5073 sanitization_techniques: self.extract_sanitization_techniques(content),
5074 });
5075 }
5076
5077 if content.contains("Pattern.compile")
5079 || content.contains("matches()")
5080 || content.contains("Regex")
5081 || content.contains("\\\\")
5082 {
5083 validation_patterns.push(InputValidationPattern {
5084 validation_type: ValidationType::RegexValidation,
5085 input_sources: vec!["String inputs".to_string()],
5086 validation_methods: vec!["Regular expression validation".to_string()],
5087 sanitization_techniques: self.extract_sanitization_techniques(content),
5088 });
5089 }
5090
5091 if content.contains("whitelist")
5093 || content.contains("allowedValues")
5094 || content.contains("VALID_")
5095 || content.contains("permitted")
5096 {
5097 validation_patterns.push(InputValidationPattern {
5098 validation_type: ValidationType::Whitelist,
5099 input_sources: vec!["User inputs".to_string()],
5100 validation_methods: vec!["Whitelist validation".to_string()],
5101 sanitization_techniques: self.extract_sanitization_techniques(content),
5102 });
5103 }
5104
5105 Ok(validation_patterns)
5106 }
5107
5108 fn analyze_cryptography(&self, content: &str) -> Result<Vec<CryptographicPattern>> {
5110 let mut crypto_patterns = Vec::new();
5111
5112 if content.contains("Cipher.getInstance")
5114 || content.contains("AES")
5115 || content.contains("RSA")
5116 || content.contains("encrypt")
5117 {
5118 let algorithm = self.extract_crypto_algorithm(content, "encryption");
5119 let key_management = self.analyze_key_management(content);
5120 let issues = self.identify_crypto_issues(content, &algorithm);
5121
5122 crypto_patterns.push(CryptographicPattern {
5123 crypto_operation: CryptographicOperation::Encryption,
5124 algorithm,
5125 key_management,
5126 implementation_issues: issues,
5127 });
5128 }
5129
5130 if content.contains("MessageDigest")
5132 || content.contains("hash")
5133 || content.contains("SHA")
5134 || content.contains("BCrypt")
5135 {
5136 let algorithm = self.extract_crypto_algorithm(content, "hashing");
5137 let key_management = self.analyze_key_management(content);
5138 let issues = self.identify_crypto_issues(content, &algorithm);
5139
5140 crypto_patterns.push(CryptographicPattern {
5141 crypto_operation: CryptographicOperation::Hashing,
5142 algorithm,
5143 key_management,
5144 implementation_issues: issues,
5145 });
5146 }
5147
5148 if content.contains("Signature.getInstance")
5150 || content.contains("sign()")
5151 || content.contains("verify()")
5152 || content.contains("DSA")
5153 {
5154 let algorithm = self.extract_crypto_algorithm(content, "signature");
5155 let key_management = self.analyze_key_management(content);
5156 let issues = self.identify_crypto_issues(content, &algorithm);
5157
5158 crypto_patterns.push(CryptographicPattern {
5159 crypto_operation: CryptographicOperation::DigitalSignature,
5160 algorithm,
5161 key_management,
5162 implementation_issues: issues,
5163 });
5164 }
5165
5166 Ok(crypto_patterns)
5167 }
5168
5169 fn analyze_web_security(&self, content: &str) -> Result<Vec<WebSecurityPattern>> {
5171 let mut web_security_patterns = Vec::new();
5172
5173 if content.contains("@EnableWebSecurity")
5175 || content.contains("csrf()")
5176 || content.contains("CsrfToken")
5177 || content.contains("_csrf")
5178 {
5179 let effectiveness = if content.contains("csrf().disable()") {
5180 SecurityEffectiveness::Missing
5181 } else if content.contains("csrfTokenRepository") {
5182 SecurityEffectiveness::Excellent
5183 } else {
5184 SecurityEffectiveness::Good
5185 };
5186
5187 web_security_patterns.push(WebSecurityPattern {
5188 security_mechanism: WebSecurityMechanism::CsrfProtection,
5189 configuration: self.extract_csrf_config(content),
5190 effectiveness,
5191 });
5192 }
5193
5194 if content.contains("X-XSS-Protection")
5196 || content.contains("htmlEscape")
5197 || content.contains("ResponseEntity")
5198 || content.contains("@ResponseBody")
5199 {
5200 let effectiveness = self.assess_xss_protection_effectiveness(content);
5201 web_security_patterns.push(WebSecurityPattern {
5202 security_mechanism: WebSecurityMechanism::XssProtection,
5203 configuration: self.extract_xss_config(content),
5204 effectiveness,
5205 });
5206 }
5207
5208 if content.contains("requiresChannel")
5210 || content.contains("HTTPS")
5211 || content.contains("redirectStrategy")
5212 || content.contains("secure: true")
5213 {
5214 web_security_patterns.push(WebSecurityPattern {
5215 security_mechanism: WebSecurityMechanism::HttpsEnforcement,
5216 configuration: self.extract_https_config(content),
5217 effectiveness: SecurityEffectiveness::Good,
5218 });
5219 }
5220
5221 if content.contains("Content-Security-Policy")
5223 || content.contains("CSP")
5224 || content.contains("X-Frame-Options")
5225 || content.contains("X-Content-Type-Options")
5226 {
5227 web_security_patterns.push(WebSecurityPattern {
5228 security_mechanism: WebSecurityMechanism::ContentSecurityPolicy,
5229 configuration: self.extract_csp_config(content),
5230 effectiveness: SecurityEffectiveness::Good,
5231 });
5232 }
5233
5234 if content.contains("@CrossOrigin")
5236 || content.contains("CorsConfiguration")
5237 || content.contains("allowedOrigins")
5238 || content.contains("Access-Control")
5239 {
5240 let effectiveness = self.assess_cors_security(content);
5241 web_security_patterns.push(WebSecurityPattern {
5242 security_mechanism: WebSecurityMechanism::CorsConfiguration,
5243 configuration: self.extract_cors_config(content),
5244 effectiveness,
5245 });
5246 }
5247
5248 Ok(web_security_patterns)
5249 }
5250
5251 fn determine_security_level(
5252 &self,
5253 vulnerabilities: &[SecurityVulnerability],
5254 _security_patterns: &[SecurityPattern],
5255 ) -> SecurityLevel {
5256 if vulnerabilities
5257 .iter()
5258 .any(|v| matches!(v.severity, SecuritySeverity::Critical))
5259 {
5260 SecurityLevel::Vulnerable
5261 } else if vulnerabilities
5262 .iter()
5263 .any(|v| matches!(v.severity, SecuritySeverity::High))
5264 {
5265 SecurityLevel::Low
5266 } else {
5267 SecurityLevel::Medium
5268 }
5269 }
5270
5271 fn generate_security_recommendations(
5272 &self,
5273 _vulnerabilities: &[SecurityVulnerability],
5274 _security_patterns: &[SecurityPattern],
5275 ) -> Vec<String> {
5276 vec![
5277 "Implement input validation for all user inputs".to_string(),
5278 "Use parameterized queries to prevent SQL injection".to_string(),
5279 "Implement proper authentication and authorization".to_string(),
5280 ]
5281 }
5282
5283 fn get_vulnerability_description(&self, vulnerability_type: &str) -> String {
5284 match vulnerability_type {
5285 "sql_injection" => "Potential SQL injection vulnerability detected".to_string(),
5286 "hardcoded_credentials" => "Hardcoded credentials found in source code".to_string(),
5287 "command_injection" => "Potential command injection vulnerability".to_string(),
5288 "path_traversal" => "Potential path traversal vulnerability".to_string(),
5289 "weak_cryptography" => "Weak cryptographic algorithm detected".to_string(),
5290 "insecure_randomness" => "Insecure random number generation".to_string(),
5291 _ => format!("Security issue: {vulnerability_type}"),
5292 }
5293 }
5294
5295 fn get_cwe_id(&self, vulnerability_type: &str) -> Option<String> {
5296 match vulnerability_type {
5297 "sql_injection" => Some("CWE-89".to_string()),
5298 "hardcoded_credentials" => Some("CWE-798".to_string()),
5299 "command_injection" => Some("CWE-78".to_string()),
5300 "path_traversal" => Some("CWE-22".to_string()),
5301 "weak_cryptography" => Some("CWE-327".to_string()),
5302 "insecure_randomness" => Some("CWE-330".to_string()),
5303 _ => None,
5304 }
5305 }
5306
5307 fn get_security_recommendation(&self, vulnerability_type: &str) -> String {
5308 match vulnerability_type {
5309 "sql_injection" => "Use parameterized queries or prepared statements".to_string(),
5310 "hardcoded_credentials" => {
5311 "Store credentials in environment variables or secure configuration".to_string()
5312 }
5313 "command_injection" => {
5314 "Validate and sanitize all input before using in system commands".to_string()
5315 }
5316 "path_traversal" => "Validate file paths and use canonicalization".to_string(),
5317 "weak_cryptography" => {
5318 "Use strong cryptographic algorithms like SHA-256 or better".to_string()
5319 }
5320 "insecure_randomness" => "Use SecureRandom for cryptographic operations".to_string(),
5321 _ => "Review and fix security vulnerability".to_string(),
5322 }
5323 }
5324
5325 fn detect_java_version(&self, content: &str) -> Result<JavaVersionInfo> {
5326 let mut features_by_version = Vec::new();
5327 let mut compatibility_issues = Vec::new();
5328 let mut minimum_version = 8;
5329
5330 if content.contains("lambda") || content.contains("->") {
5332 features_by_version.push(VersionFeatureInfo {
5333 feature_name: "Lambda expressions".to_string(),
5334 java_version: "8".to_string(),
5335 usage_count: content.matches("->").count(),
5336 is_best_practice: true,
5337 });
5338 minimum_version = minimum_version.max(8);
5339 }
5340
5341 if content.contains(".stream()") || content.contains("Stream<") {
5342 features_by_version.push(VersionFeatureInfo {
5343 feature_name: "Stream API".to_string(),
5344 java_version: "8".to_string(),
5345 usage_count: content.matches(".stream()").count(),
5346 is_best_practice: true,
5347 });
5348 minimum_version = minimum_version.max(8);
5349 }
5350
5351 if content.contains("Optional<") {
5352 features_by_version.push(VersionFeatureInfo {
5353 feature_name: "Optional".to_string(),
5354 java_version: "8".to_string(),
5355 usage_count: content.matches("Optional<").count(),
5356 is_best_practice: true,
5357 });
5358 minimum_version = minimum_version.max(8);
5359 }
5360
5361 if content.contains("var ") {
5363 features_by_version.push(VersionFeatureInfo {
5364 feature_name: "Local variable type inference (var)".to_string(),
5365 java_version: "10".to_string(),
5366 usage_count: Regex::new(r"\bvar\s+\w+\s*=")
5367 .unwrap()
5368 .find_iter(content)
5369 .count(),
5370 is_best_practice: true,
5371 });
5372 minimum_version = minimum_version.max(10);
5373 }
5374
5375 if content.contains("switch") && content.contains("->") {
5377 features_by_version.push(VersionFeatureInfo {
5378 feature_name: "Switch expressions".to_string(),
5379 java_version: "12".to_string(),
5380 usage_count: content.matches("switch").count(),
5381 is_best_practice: true,
5382 });
5383 minimum_version = minimum_version.max(12);
5384 }
5385
5386 if content.contains("\"\"\"") {
5388 features_by_version.push(VersionFeatureInfo {
5389 feature_name: "Text blocks".to_string(),
5390 java_version: "13".to_string(),
5391 usage_count: content.matches("\"\"\"").count() / 2, is_best_practice: true,
5393 });
5394 minimum_version = minimum_version.max(13);
5395 }
5396
5397 if content.contains("record ") {
5399 features_by_version.push(VersionFeatureInfo {
5400 feature_name: "Record classes".to_string(),
5401 java_version: "14".to_string(),
5402 usage_count: Regex::new(r"\brecord\s+\w+")
5403 .unwrap()
5404 .find_iter(content)
5405 .count(),
5406 is_best_practice: true,
5407 });
5408 minimum_version = minimum_version.max(14);
5409 }
5410
5411 if content.contains("sealed ") {
5413 features_by_version.push(VersionFeatureInfo {
5414 feature_name: "Sealed classes".to_string(),
5415 java_version: "17".to_string(),
5416 usage_count: Regex::new(r"\bsealed\s+(?:class|interface)")
5417 .unwrap()
5418 .find_iter(content)
5419 .count(),
5420 is_best_practice: true,
5421 });
5422 minimum_version = minimum_version.max(17);
5423 }
5424
5425 if content.contains("new Date()") || content.contains("Calendar.getInstance()") {
5427 compatibility_issues.push(CompatibilityIssue {
5428 issue_type: CompatibilityIssueType::DeprecatedFeature,
5429 required_version: "8".to_string(),
5430 current_version: minimum_version.to_string(),
5431 affected_features: vec!["Legacy Date/Time API".to_string()],
5432 });
5433 }
5434
5435 Ok(JavaVersionInfo {
5436 minimum_version_required: minimum_version.to_string(),
5437 features_by_version,
5438 compatibility_issues,
5439 })
5440 }
5441
5442 fn analyze_stream_api(&self, content: &str) -> Result<Vec<StreamApiUsageInfo>> {
5443 let mut stream_usages = Vec::new();
5444
5445 let stream_regex = Regex::new(r"(\w+)\.stream\(\)([^;]+);")?;
5447
5448 for captures in stream_regex.captures_iter(content) {
5449 let stream_source = captures.get(1).unwrap().as_str().to_string();
5450 let operations_chain = captures.get(2).unwrap().as_str();
5451
5452 let mut operations = Vec::new();
5454 let operation_patterns = [
5455 ("filter", StreamOperationType::Intermediate),
5456 ("map", StreamOperationType::Intermediate),
5457 ("flatMap", StreamOperationType::Intermediate),
5458 ("distinct", StreamOperationType::Intermediate),
5459 ("sorted", StreamOperationType::Intermediate),
5460 ("peek", StreamOperationType::Intermediate),
5461 ("limit", StreamOperationType::Intermediate),
5462 ("skip", StreamOperationType::Intermediate),
5463 ("collect", StreamOperationType::Terminal),
5464 ("forEach", StreamOperationType::Terminal),
5465 ("reduce", StreamOperationType::Terminal),
5466 ("findFirst", StreamOperationType::Terminal),
5467 ("findAny", StreamOperationType::Terminal),
5468 ("anyMatch", StreamOperationType::Terminal),
5469 ("allMatch", StreamOperationType::Terminal),
5470 ("noneMatch", StreamOperationType::Terminal),
5471 ("count", StreamOperationType::Terminal),
5472 ("max", StreamOperationType::Terminal),
5473 ("min", StreamOperationType::Terminal),
5474 ];
5475
5476 for (op_name, op_type) in operation_patterns {
5477 if operations_chain.contains(op_name) {
5478 operations.push(StreamOperation {
5479 operation_type: op_type.clone(),
5480 operation_name: op_name.to_string(),
5481 parameters: Vec::new(), });
5483 }
5484 }
5485
5486 let terminal_operation = operations
5488 .iter()
5489 .find(|op| matches!(op.operation_type, StreamOperationType::Terminal))
5490 .map(|op| op.operation_name.clone())
5491 .unwrap_or_else(|| "Unknown".to_string());
5492
5493 let parallel_usage = operations_chain.contains(".parallel()");
5495
5496 let performance_characteristics = if operations.len() > 5 {
5498 StreamPerformance::Poor
5499 } else if operations.len() > 3 {
5500 StreamPerformance::Fair
5501 } else if operations.iter().any(|op| op.operation_name == "sorted") {
5502 StreamPerformance::Good
5503 } else {
5504 StreamPerformance::Optimal
5505 };
5506
5507 let complexity = match operations.len() {
5509 0..=2 => StreamComplexity::Simple,
5510 3..=4 => StreamComplexity::Moderate,
5511 5..=7 => StreamComplexity::Complex,
5512 _ => StreamComplexity::VeryComplex,
5513 };
5514
5515 stream_usages.push(StreamApiUsageInfo {
5516 stream_source,
5517 operations,
5518 terminal_operation,
5519 parallel_usage,
5520 performance_characteristics,
5521 complexity,
5522 });
5523 }
5524
5525 Ok(stream_usages)
5526 }
5527
5528 fn analyze_optional_usage(&self, content: &str) -> Result<Vec<OptionalUsageInfo>> {
5529 let mut optional_usages = Vec::new();
5530
5531 let optional_regex = Regex::new(r"Optional<([^>]+)>\s+(\w+)")?;
5533
5534 for captures in optional_regex.captures_iter(content) {
5535 let optional_type = captures.get(1).unwrap().as_str().to_string();
5536 let variable_name = captures.get(2).unwrap().as_str().to_string();
5537
5538 let usage_pattern = if content.contains(&format!("return {variable_name};")) {
5540 OptionalUsagePattern::ReturnValue
5541 } else if content.contains(&format!("{variable_name}.map("))
5542 || content.contains(&format!("{variable_name}.flatMap("))
5543 {
5544 OptionalUsagePattern::ChainedCalls
5545 } else {
5546 OptionalUsagePattern::ParameterValue
5547 };
5548
5549 let mut anti_patterns = Vec::new();
5551 if content.contains(&format!("{variable_name}.get()")) {
5552 anti_patterns.push(OptionalAntiPattern::CallingGet);
5553 }
5554 if content.contains(&format!("{variable_name}.isPresent()")) {
5555 anti_patterns.push(OptionalAntiPattern::UsingIsPresent);
5556 }
5557
5558 if content.contains("return null;") {
5560 anti_patterns.push(OptionalAntiPattern::ReturningNull);
5561 }
5562
5563 optional_usages.push(OptionalUsageInfo {
5564 usage_context: format!("Optional<{optional_type}> usage"),
5565 optional_type,
5566 usage_pattern,
5567 anti_patterns,
5568 });
5569 }
5570
5571 Ok(optional_usages)
5572 }
5573
5574 fn analyze_module_system(&self, content: &str) -> Result<Option<ModuleSystemInfo>> {
5575 if content.contains("module ") && content.contains("requires ") {
5577 let module_regex = Regex::new(r"module\s+([^\s{]+)")?;
5578 let module_name = module_regex
5579 .captures(content)
5580 .and_then(|cap| cap.get(1))
5581 .map(|m| m.as_str().to_string())
5582 .unwrap_or_else(|| "unknown".to_string());
5583
5584 let exports_regex = Regex::new(r"exports\s+([^;]+);")?;
5586 let exports = exports_regex
5587 .captures_iter(content)
5588 .map(|cap| cap.get(1).unwrap().as_str().trim().to_string())
5589 .collect();
5590
5591 let requires_regex = Regex::new(r"requires\s+([^;]+);")?;
5593 let requires = requires_regex
5594 .captures_iter(content)
5595 .map(|cap| cap.get(1).unwrap().as_str().trim().to_string())
5596 .collect();
5597
5598 let provides_regex = Regex::new(r"provides\s+([^;]+);")?;
5600 let provides = provides_regex
5601 .captures_iter(content)
5602 .map(|cap| cap.get(1).unwrap().as_str().trim().to_string())
5603 .collect();
5604
5605 let uses_regex = Regex::new(r"uses\s+([^;]+);")?;
5607 let uses = uses_regex
5608 .captures_iter(content)
5609 .map(|cap| cap.get(1).unwrap().as_str().trim().to_string())
5610 .collect();
5611
5612 let opens_regex = Regex::new(r"opens\s+([^;]+);")?;
5614 let opens = opens_regex
5615 .captures_iter(content)
5616 .map(|cap| cap.get(1).unwrap().as_str().trim().to_string())
5617 .collect();
5618
5619 Ok(Some(ModuleSystemInfo {
5620 module_name,
5621 exports,
5622 requires,
5623 provides,
5624 uses,
5625 opens,
5626 }))
5627 } else {
5628 Ok(None)
5629 }
5630 }
5631
5632 fn analyze_record_classes(&self, content: &str) -> Result<Vec<RecordClassInfo>> {
5633 let mut records = Vec::new();
5634
5635 let record_regex = Regex::new(r"(?m)^(?:\s*public\s+)?record\s+(\w+)\s*\(([^)]*)\)")?;
5637
5638 for captures in record_regex.captures_iter(content) {
5639 let record_name = captures.get(1).unwrap().as_str().to_string();
5640 let components_str = captures.get(2).unwrap().as_str();
5641
5642 let mut components = Vec::new();
5644 if !components_str.trim().is_empty() {
5645 for component in components_str.split(',') {
5646 let component = component.trim();
5647 if let Some(space_idx) = component.rfind(' ') {
5648 let component_type = component[..space_idx].trim().to_string();
5649 let name = component[space_idx + 1..].trim().to_string();
5650
5651 let annotations = if component.contains('@') {
5653 vec!["@NotNull".to_string()] } else {
5655 Vec::new()
5656 };
5657
5658 components.push(RecordComponent {
5659 name,
5660 component_type,
5661 annotations,
5662 });
5663 }
5664 }
5665 }
5666
5667 let record_content = self.extract_class_content(content, &record_name);
5669 let method_regex = Regex::new(r"(?:public|private|protected)\s+\w+\s+(\w+)\s*\(")?;
5670 let additional_methods = method_regex
5671 .captures_iter(&record_content)
5672 .map(|cap| cap.get(1).unwrap().as_str().to_string())
5673 .filter(|name| !components.iter().any(|comp| comp.name == *name))
5674 .collect();
5675
5676 let implements_regex = Regex::new(&format!(
5678 r"record\s+{record_name}\s*\([^)]*\)\s*implements\s+([\w\s,]+)"
5679 ))?;
5680 let implements_interfaces = if let Some(captures) = implements_regex.captures(content) {
5681 captures
5682 .get(1)
5683 .unwrap()
5684 .as_str()
5685 .split(',')
5686 .map(|s| s.trim().to_string())
5687 .collect()
5688 } else {
5689 Vec::new()
5690 };
5691
5692 records.push(RecordClassInfo {
5693 record_name,
5694 components,
5695 additional_methods,
5696 implements_interfaces,
5697 });
5698 }
5699
5700 Ok(records)
5701 }
5702
5703 fn analyze_sealed_classes(&self, content: &str) -> Result<Vec<SealedClassInfo>> {
5704 let mut sealed_classes = Vec::new();
5705
5706 let sealed_class_regex =
5708 Regex::new(r"sealed\s+(class|interface)\s+(\w+).*permits\s+([\w\s,]+)")?;
5709
5710 for captures in sealed_class_regex.captures_iter(content) {
5711 let sealing_type = match captures.get(1).unwrap().as_str() {
5712 "class" => SealingType::SealedClass,
5713 "interface" => SealingType::SealedInterface,
5714 _ => SealingType::SealedClass,
5715 };
5716
5717 let sealed_class_name = captures.get(2).unwrap().as_str().to_string();
5718 let permitted_str = captures.get(3).unwrap().as_str();
5719
5720 let permitted_subclasses = permitted_str
5721 .split(',')
5722 .map(|s| s.trim().to_string())
5723 .collect();
5724
5725 sealed_classes.push(SealedClassInfo {
5726 sealed_class_name,
5727 permitted_subclasses,
5728 sealing_type,
5729 });
5730 }
5731
5732 Ok(sealed_classes)
5733 }
5734
5735 fn analyze_switch_expressions(&self, content: &str) -> Result<Vec<SwitchExpressionInfo>> {
5736 let mut switch_expressions = Vec::new();
5737
5738 let switch_regex = Regex::new(r"switch\s*\(([^)]+)\)\s*\{([^}]+)\}")?;
5740
5741 for captures in switch_regex.captures_iter(content) {
5742 let switch_type = captures.get(1).unwrap().as_str().to_string();
5743 let switch_body = captures.get(2).unwrap().as_str();
5744
5745 let arrow_syntax = switch_body.contains("->");
5747
5748 let has_yield = switch_body.contains("yield");
5750
5751 let pattern_matching =
5753 switch_body.contains("instanceof") || switch_body.contains("when") || arrow_syntax;
5754
5755 let exhaustiveness =
5757 switch_body.contains("default") || (switch_body.matches("case").count() > 3);
5758
5759 switch_expressions.push(SwitchExpressionInfo {
5760 switch_type,
5761 has_yield,
5762 pattern_matching,
5763 exhaustiveness,
5764 arrow_syntax,
5765 });
5766 }
5767
5768 Ok(switch_expressions)
5769 }
5770
5771 fn analyze_text_blocks(&self, content: &str) -> Result<Vec<TextBlockInfo>> {
5772 let mut text_blocks = Vec::new();
5773
5774 let text_block_regex = Regex::new(r#""{3}(.*?)"{3}"#)?;
5776
5777 for captures in text_block_regex.captures_iter(content) {
5778 let text_content = captures.get(1).unwrap().as_str();
5779
5780 let content_type = if text_content.trim_start().starts_with('{') {
5782 TextBlockContentType::Json
5783 } else if text_content.trim_start().starts_with('<') {
5784 if text_content.contains("<!DOCTYPE") || text_content.contains("<html") {
5785 TextBlockContentType::Html
5786 } else {
5787 TextBlockContentType::Xml
5788 }
5789 } else if text_content.to_uppercase().contains("SELECT")
5790 || text_content.to_uppercase().contains("INSERT")
5791 || text_content.to_uppercase().contains("UPDATE")
5792 {
5793 TextBlockContentType::Sql
5794 } else {
5795 TextBlockContentType::PlainText
5796 };
5797
5798 let line_count = text_content.lines().count();
5799
5800 let escape_sequences_used = vec![
5802 ("\\n", "Line feed"),
5803 ("\\t", "Tab"),
5804 ("\\r", "Carriage return"),
5805 ("\\\"", "Quote"),
5806 ("\\\\", "Backslash"),
5807 ]
5808 .into_iter()
5809 .filter_map(|(seq, desc)| {
5810 if text_content.contains(seq) {
5811 Some(desc.to_string())
5812 } else {
5813 None
5814 }
5815 })
5816 .collect();
5817
5818 text_blocks.push(TextBlockInfo {
5819 content_type,
5820 line_count,
5821 indentation_stripped: true, escape_sequences_used,
5823 });
5824 }
5825
5826 Ok(text_blocks)
5827 }
5828
5829 fn analyze_var_usage(&self, content: &str) -> Result<Vec<VarUsageInfo>> {
5830 let mut var_usages = Vec::new();
5831
5832 let var_regex = Regex::new(r"\bvar\s+(\w+)\s*=\s*([^;]+);")?;
5834
5835 for captures in var_regex.captures_iter(content) {
5836 let var_name = captures.get(1).unwrap().as_str();
5837 let initializer = captures.get(2).unwrap().as_str().trim();
5838
5839 let usage_context = if content.contains(&format!("for (var {var_name}")) {
5841 VarUsageContext::ForLoop
5842 } else if content.contains(&format!("try (var {var_name}")) {
5843 VarUsageContext::TryWithResources
5844 } else if initializer.contains("->") {
5845 VarUsageContext::LambdaParameter
5846 } else {
5847 VarUsageContext::LocalVariable
5848 };
5849
5850 let inferred_type = if initializer.starts_with("new ") {
5852 if let Some(type_end) = initializer.find('(') {
5853 initializer[4..type_end].trim().to_string()
5854 } else {
5855 "Object".to_string()
5856 }
5857 } else if initializer.starts_with('"') {
5858 "String".to_string()
5859 } else if initializer.parse::<i32>().is_ok() {
5860 "int".to_string()
5861 } else if initializer.parse::<f64>().is_ok() {
5862 "double".to_string()
5863 } else if initializer == "true" || initializer == "false" {
5864 "boolean".to_string()
5865 } else {
5866 "Unknown".to_string()
5867 };
5868
5869 let appropriate_usage = inferred_type != "Unknown"
5871 && !initializer.contains("null")
5872 && initializer.len() > var_name.len(); var_usages.push(VarUsageInfo {
5875 usage_context,
5876 inferred_type,
5877 appropriate_usage,
5878 });
5879 }
5880
5881 Ok(var_usages)
5882 }
5883
5884 fn analyze_completable_future(&self, content: &str) -> Result<Vec<CompletableFutureInfo>> {
5885 let mut completable_futures = Vec::new();
5886
5887 if content.contains("CompletableFuture") {
5889 if content.contains("CompletableFuture.supplyAsync") {
5891 completable_futures.push(CompletableFutureInfo {
5892 usage_pattern: CompletableFuturePattern::SimpleAsync,
5893 chaining_complexity: self.count_completable_future_chains(content),
5894 exception_handling: content.contains("exceptionally")
5895 || content.contains("handle"),
5896 thread_pool_usage: self.extract_executor_usage(content),
5897 });
5898 }
5899
5900 if content.contains("thenApply")
5902 || content.contains("thenCompose")
5903 || content.contains("thenCombine")
5904 {
5905 completable_futures.push(CompletableFutureInfo {
5906 usage_pattern: CompletableFuturePattern::Chaining,
5907 chaining_complexity: self.count_completable_future_chains(content),
5908 exception_handling: content.contains("exceptionally")
5909 || content.contains("handle"),
5910 thread_pool_usage: self.extract_executor_usage(content),
5911 });
5912 }
5913
5914 if content.contains("allOf")
5916 || content.contains("anyOf")
5917 || content.contains("thenCombine")
5918 {
5919 completable_futures.push(CompletableFutureInfo {
5920 usage_pattern: CompletableFuturePattern::Combining,
5921 chaining_complexity: self.count_completable_future_chains(content),
5922 exception_handling: content.contains("exceptionally")
5923 || content.contains("handle"),
5924 thread_pool_usage: self.extract_executor_usage(content),
5925 });
5926 }
5927 }
5928
5929 Ok(completable_futures)
5930 }
5931
5932 fn analyze_date_time_api(&self, content: &str) -> Result<Vec<DateTimeApiInfo>> {
5933 let mut date_time_usages = Vec::new();
5934
5935 let api_types = [
5936 ("LocalDateTime", DateTimeApiType::LocalDateTime),
5937 ("ZonedDateTime", DateTimeApiType::ZonedDateTime),
5938 ("Instant", DateTimeApiType::Instant),
5939 ("Duration", DateTimeApiType::Duration),
5940 ("Period", DateTimeApiType::Period),
5941 ("DateTimeFormatter", DateTimeApiType::DateTimeFormatter),
5942 ("Date", DateTimeApiType::Legacy), ("Calendar", DateTimeApiType::Legacy),
5944 ];
5945
5946 for (api_name, api_type) in api_types {
5947 if content.contains(api_name) {
5948 let usage_patterns = self.extract_date_time_patterns(content, api_name);
5950
5951 let timezone_handling = content.contains("ZoneId") || content.contains("TimeZone");
5953
5954 let formatting_patterns = self.extract_formatting_patterns(content);
5956
5957 date_time_usages.push(DateTimeApiInfo {
5958 api_type,
5959 usage_patterns,
5960 timezone_handling,
5961 formatting_patterns,
5962 });
5963 }
5964 }
5965
5966 Ok(date_time_usages)
5967 }
5968
5969 fn analyze_collection_factories(&self, content: &str) -> Result<Vec<CollectionFactoryInfo>> {
5970 let mut factory_usages = Vec::new();
5971
5972 let factory_patterns = [
5974 ("List.of", "List"),
5975 ("Set.of", "Set"),
5976 ("Map.of", "Map"),
5977 ("Arrays.asList", "List"),
5978 ("Collections.singletonList", "List"),
5979 ("Collections.emptyList", "List"),
5980 ("Collections.emptySet", "Set"),
5981 ("Collections.emptyMap", "Map"),
5982 ];
5983
5984 for (factory_method, collection_type) in factory_patterns {
5985 let pattern = format!(r"{factory_method}\s*\(([^)]*)\)");
5986 let factory_regex = Regex::new(&pattern).unwrap();
5987
5988 for captures in factory_regex.captures_iter(content) {
5989 let args = captures.get(1).unwrap().as_str();
5990 let element_count = if args.trim().is_empty() {
5991 0
5992 } else {
5993 args.split(',').count()
5994 };
5995
5996 let immutability = factory_method.contains(".of")
5998 || factory_method.contains("singleton")
5999 || factory_method.contains("empty");
6000
6001 factory_usages.push(CollectionFactoryInfo {
6002 factory_method: factory_method.to_string(),
6003 collection_type: collection_type.to_string(),
6004 element_count,
6005 immutability,
6006 });
6007 }
6008 }
6009
6010 Ok(factory_usages)
6011 }
6012
6013 fn calculate_modernity_score(&self, content: &str) -> i32 {
6014 let mut score = 0;
6015
6016 if content.contains("->") {
6018 score += 15;
6019 }
6020
6021 if content.contains(".stream()") {
6023 score += 15;
6024 }
6025
6026 if content.contains("Optional<") {
6028 score += 10;
6029 }
6030
6031 if content.contains("LocalDateTime") || content.contains("ZonedDateTime") {
6033 score += 10;
6034 }
6035
6036 if content.contains("var ") {
6038 score += 10;
6039 }
6040
6041 if content.contains("switch") && content.contains("->") {
6043 score += 10;
6044 }
6045
6046 if content.contains("\"\"\"") {
6048 score += 10;
6049 }
6050
6051 if content.contains("record ") {
6053 score += 15;
6054 }
6055
6056 if content.contains("sealed ") {
6058 score += 15;
6059 }
6060
6061 if content.contains("instanceof") && content.contains("&&") {
6063 score += 5;
6064 }
6065
6066 if content.contains("new Date()") || content.contains("Calendar.getInstance()") {
6068 score -= 10;
6069 }
6070
6071 if content.contains("Vector") || content.contains("Hashtable") {
6072 score -= 5;
6073 }
6074
6075 score.max(0).min(100)
6076 }
6077
6078 fn count_completable_future_chains(&self, content: &str) -> i32 {
6080 let chain_methods = [
6081 "thenApply",
6082 "thenCompose",
6083 "thenAccept",
6084 "thenRun",
6085 "thenCombine",
6086 ];
6087 chain_methods
6088 .iter()
6089 .map(|method| content.matches(method).count() as i32)
6090 .sum()
6091 }
6092
6093 fn extract_executor_usage(&self, content: &str) -> Option<String> {
6094 if content.contains("ForkJoinPool") {
6095 Some("ForkJoinPool".to_string())
6096 } else if content.contains("ThreadPoolExecutor") {
6097 Some("ThreadPoolExecutor".to_string())
6098 } else if content.contains("Executors.") {
6099 Some("Executors framework".to_string())
6100 } else {
6101 None
6102 }
6103 }
6104
6105 fn extract_date_time_patterns(&self, content: &str, api_name: &str) -> Vec<String> {
6106 let mut patterns = Vec::new();
6107
6108 if content.contains(&format!("{api_name}.now()")) {
6109 patterns.push("Current time creation".to_string());
6110 }
6111 if content.contains(&format!("{api_name}.of(")) {
6112 patterns.push("Specific time creation".to_string());
6113 }
6114 if content.contains(&format!("{api_name}.parse(")) {
6115 patterns.push("String parsing".to_string());
6116 }
6117 if content.contains(".format(") {
6118 patterns.push("Time formatting".to_string());
6119 }
6120
6121 patterns
6122 }
6123
6124 fn extract_formatting_patterns(&self, content: &str) -> Vec<String> {
6125 let mut patterns = Vec::new();
6126
6127 if content.contains("DateTimeFormatter.ofPattern") {
6128 patterns.push("Custom pattern formatting".to_string());
6129 }
6130 if content.contains("DateTimeFormatter.ISO_") {
6131 patterns.push("ISO standard formatting".to_string());
6132 }
6133 if content.contains("SimpleDateFormat") {
6134 patterns.push("Legacy SimpleDateFormat".to_string());
6135 }
6136
6137 patterns
6138 }
6139
6140 fn infer_functional_interface(&self, _content: &str, _position: usize) -> String {
6142 "Unknown".to_string()
6143 }
6144
6145 fn assess_lambda_complexity(&self, lambda_text: &str) -> LambdaComplexity {
6146 if lambda_text.len() < 20 {
6147 LambdaComplexity::Simple
6148 } else if lambda_text.len() < 50 {
6149 LambdaComplexity::Moderate
6150 } else {
6151 LambdaComplexity::Complex
6152 }
6153 }
6154
6155 fn checks_variable_capture(&self, _content: &str, _start: usize, _end: usize) -> bool {
6156 false
6157 }
6158
6159 fn get_lambda_context(&self, _content: &str, _position: usize) -> String {
6160 "Unknown context".to_string()
6161 }
6162
6163 fn assess_lambda_performance_impact(&self, _lambda_text: &str) -> PerformanceImpact {
6164 PerformanceImpact::Neutral
6165 }
6166
6167 fn analyze_algorithm_complexity(&self, _content: &str) -> Result<Vec<ComplexityAnalysis>> {
6168 Ok(vec![ComplexityAnalysis {
6169 method_name: "sample_method".to_string(),
6170 time_complexity: "O(n)".to_string(),
6171 space_complexity: "O(1)".to_string(),
6172 complexity_score: 70,
6173 recommendations: vec!["Consider optimization".to_string()],
6174 }])
6175 }
6176
6177 fn analyze_collection_usage(&self, _content: &str) -> Result<Vec<CollectionUsageInfo>> {
6178 Ok(vec![CollectionUsageInfo {
6179 collection_type: "ArrayList".to_string(),
6180 usage_pattern: "Standard iteration".to_string(),
6181 efficiency_rating: EfficiencyRating::Good,
6182 recommendations: vec!["Consider using Stream API".to_string()],
6183 }])
6184 }
6185
6186 fn analyze_memory_patterns(&self, _content: &str) -> Result<Vec<MemoryPatternInfo>> {
6187 Ok(vec![MemoryPatternInfo {
6188 pattern_type: MemoryPatternType::LazyInitialization,
6189 impact: MemoryImpact::Positive,
6190 location: "General patterns".to_string(),
6191 recommendations: vec!["Good memory usage detected".to_string()],
6192 }])
6193 }
6194
6195 fn analyze_concurrency_patterns(&self, _content: &str) -> Result<Vec<ConcurrencyPatternInfo>> {
6196 Ok(vec![ConcurrencyPatternInfo {
6197 pattern_type: ConcurrencyPatternType::Synchronization,
6198 thread_safety: ThreadSafety::ThreadSafe,
6199 performance_impact: PerformanceImpact::Neutral,
6200 recommendations: vec!["Review thread safety".to_string()],
6201 }])
6202 }
6203
6204 fn identify_performance_issues(&self, _content: &str) -> Result<Vec<PerformanceIssue>> {
6205 Ok(vec![PerformanceIssue {
6206 issue_type: PerformanceIssueType::InEfficientQuery,
6207 severity: IssueSeverity::Medium,
6208 location: "General code".to_string(),
6209 description: "Potential optimization opportunities".to_string(),
6210 recommendation: "Review algorithm efficiency".to_string(),
6211 }])
6212 }
6213
6214 fn identify_optimization_opportunities(
6215 &self,
6216 _content: &str,
6217 ) -> Result<Vec<OptimizationOpportunity>> {
6218 Ok(vec![OptimizationOpportunity {
6219 opportunity_type: OptimizationType::AlgorithmImprovement,
6220 potential_impact: ImpactLevel::Medium,
6221 description: "Consider algorithm optimization".to_string(),
6222 implementation_difficulty: DifficultyLevel::Medium,
6223 recommendations: vec!["Review loops and data structures".to_string()],
6224 }])
6225 }
6226
6227 fn calculate_performance_score(
6228 &self,
6229 _algorithm_complexity: &[ComplexityAnalysis],
6230 _performance_issues: &[PerformanceIssue],
6231 _optimization_opportunities: &[OptimizationOpportunity],
6232 ) -> i32 {
6233 75 }
6235
6236 fn has_external_variable_references(&self, _content: &str, _start: usize, _end: usize) -> bool {
6237 false
6238 }
6239
6240 fn extract_usage_context(&self, _content: &str, _position: usize) -> String {
6241 "Unknown context".to_string()
6242 }
6243
6244 fn extract_pointcuts(&self, _content: &str, _aspect_class: &str) -> Vec<String> {
6245 vec!["execution(* com.example..*.*(..))".to_string()]
6246 }
6247
6248 fn extract_advice_types(&self, _content: &str, _aspect_class: &str) -> Vec<AdviceType> {
6249 vec![AdviceType::Before, AdviceType::After]
6250 }
6251
6252 fn identify_cross_cutting_concerns(&self, _content: &str, _aspect_class: &str) -> Vec<String> {
6253 vec!["Logging".to_string(), "Security".to_string()]
6254 }
6255
6256 fn extract_transaction_attribute(&self, _annotation: &str, _attribute: &str) -> Option<String> {
6257 Some("REQUIRED".to_string())
6258 }
6259
6260 fn extract_rollback_rules(&self, _annotation: &str) -> Vec<String> {
6261 vec!["RuntimeException.class".to_string()]
6262 }
6263
6264 fn extract_authentication_mechanisms(&self, _content: &str) -> Vec<String> {
6265 vec!["Form-based".to_string(), "JWT".to_string()]
6266 }
6267
6268 fn extract_authorization_patterns(&self, _content: &str) -> Vec<String> {
6269 vec!["Role-based".to_string()]
6270 }
6271
6272 fn extract_security_configurations(&self, _content: &str) -> Vec<String> {
6273 vec!["CSRF enabled".to_string()]
6274 }
6275
6276 fn extract_session_management(&self, _content: &str) -> String {
6277 "Default session management".to_string()
6278 }
6279
6280 fn extract_database_operations(&self, _content: &str, _class_name: &str) -> Vec<String> {
6281 vec!["findAll".to_string(), "save".to_string()]
6282 }
6283
6284 fn extract_query_methods(
6285 &self,
6286 _content: &str,
6287 _class_name: &str,
6288 ) -> Result<Vec<QueryMethodInfo>> {
6289 Ok(vec![QueryMethodInfo {
6290 method_name: "findByName".to_string(),
6291 query_type: QueryType::DerivedQuery,
6292 custom_query: None,
6293 parameters: vec!["String name".to_string()],
6294 return_type: "List<Entity>".to_string(),
6295 }])
6296 }
6297
6298 fn extract_jdbc_operations(&self, _content: &str, _class_name: &str) -> Vec<String> {
6299 vec!["query".to_string(), "update".to_string()]
6300 }
6301
6302 fn analyze_jpa_entities(&self, _content: &str) -> Result<Vec<JPAEntityInfo>> {
6303 Ok(vec![JPAEntityInfo {
6304 entity_name: "SampleEntity".to_string(),
6305 table_name: "sample_table".to_string(),
6306 primary_key: vec!["id".to_string()],
6307 fields: vec![],
6308 annotations: vec!["@Entity".to_string()],
6309 inheritance_strategy: None,
6310 }])
6311 }
6312
6313 fn analyze_entity_relationships(&self, _content: &str) -> Result<Vec<EntityRelationshipInfo>> {
6314 Ok(vec![EntityRelationshipInfo {
6315 relationship_type: RelationshipType::OneToMany,
6316 source_entity: "Parent".to_string(),
6317 target_entity: "Child".to_string(),
6318 fetch_type: FetchType::Lazy,
6319 cascade_operations: vec![CascadeType::All],
6320 bidirectional: true,
6321 }])
6322 }
6323
6324 fn analyze_jpa_queries(&self, _content: &str) -> Result<Vec<JPAQueryInfo>> {
6325 Ok(vec![JPAQueryInfo {
6326 query_type: JPAQueryType::JPQL,
6327 query_string: "SELECT e FROM Entity e".to_string(),
6328 parameters: vec![],
6329 result_type: "List<Entity>".to_string(),
6330 potential_issues: vec![],
6331 }])
6332 }
6333
6334 fn identify_jpa_performance_issues(&self, _content: &str) -> Result<Vec<PerformanceIssue>> {
6335 Ok(vec![PerformanceIssue {
6336 issue_type: PerformanceIssueType::LazyLoadingIssue,
6337 severity: IssueSeverity::Medium,
6338 location: "Entity relationships".to_string(),
6339 description: "Potential N+1 query issue".to_string(),
6340 recommendation: "Consider fetch joins".to_string(),
6341 }])
6342 }
6343
6344 fn analyze_jpa_configuration(&self, _content: &str) -> Result<JPAConfigurationInfo> {
6345 Ok(JPAConfigurationInfo {
6346 hibernate_dialect: Some("H2Dialect".to_string()),
6347 show_sql: false,
6348 format_sql: false,
6349 ddl_auto: Some("create-drop".to_string()),
6350 cache_configuration: vec![],
6351 connection_pool_settings: vec![],
6352 })
6353 }
6354
6355 fn extract_test_classes(&self, _content: &str) -> Result<Vec<TestClassInfo>> {
6356 Ok(vec![TestClassInfo {
6357 class_name: "SampleTest".to_string(),
6358 test_methods: vec![],
6359 setup_methods: vec!["setUp".to_string()],
6360 teardown_methods: vec!["tearDown".to_string()],
6361 annotations: vec!["@Test".to_string()],
6362 }])
6363 }
6364
6365 fn analyze_test_patterns(&self, _content: &str) -> Vec<TestPatternInfo> {
6366 vec![TestPatternInfo {
6367 pattern_type: TestPatternType::ArrangeActAssert,
6368 usage_count: 5,
6369 classes_using: vec!["SampleTest".to_string()],
6370 }]
6371 }
6372
6373 fn detect_mocking_frameworks(&self, _content: &str) -> Vec<MockingFrameworkInfo> {
6374 vec![MockingFrameworkInfo {
6375 framework_name: "Mockito".to_string(),
6376 version: Some("4.0".to_string()),
6377 usage_patterns: vec!["@Mock".to_string()],
6378 mock_objects: vec!["MockedService".to_string()],
6379 }]
6380 }
6381
6382 fn analyze_coverage_patterns(&self, _content: &str) -> Vec<String> {
6383 vec!["Unit tests".to_string(), "Integration tests".to_string()]
6384 }
6385
6386 fn calculate_junit_best_practices_score(&self, _content: &str) -> i32 {
6387 80 }
6389
6390 fn extract_maven_dependencies_from_imports(&self, _content: &str) -> Vec<MavenDependencyInfo> {
6391 vec![MavenDependencyInfo {
6392 group_id: "org.springframework".to_string(),
6393 artifact_id: "spring-boot-starter".to_string(),
6394 version: "2.7.0".to_string(),
6395 scope: "compile".to_string(),
6396 dependency_type: "jar".to_string(),
6397 transitive_dependencies: vec![],
6398 }]
6399 }
6400
6401 fn extract_gradle_dependencies_from_imports(
6402 &self,
6403 _content: &str,
6404 ) -> Vec<GradleDependencyInfo> {
6405 vec![GradleDependencyInfo {
6406 configuration: "implementation".to_string(),
6407 group: "org.springframework".to_string(),
6408 name: "spring-boot-starter".to_string(),
6409 version: "2.7.0".to_string(),
6410 dependency_type: "jar".to_string(),
6411 }]
6412 }
6413}
6414
6415impl Default for JavaAnalyzer {
6416 fn default() -> Self {
6417 Self::new()
6418 }
6419}
6420
6421#[cfg(test)]
6422mod tests {
6423 use super::*;
6424
6425 #[test]
6426 fn test_calculate_overall_score_returns_real_calculation() {
6427 let analyzer = JavaAnalyzer::new();
6431
6432 let test_java_code = r#"
6434public class UserService {
6435 // Good OOP: Private fields with proper encapsulation
6436 private final UserRepository repository;
6437 private final UserValidator validator;
6438
6439 // Constructor injection (good DI pattern)
6440 public UserService(UserRepository repository, UserValidator validator) {
6441 this.repository = repository;
6442 this.validator = validator;
6443 }
6444
6445 // Modern Java features (Java 8+)
6446 public Optional<User> findUser(String email) {
6447 return repository.findByEmail(email)
6448 .filter(user -> validator.isValid(user))
6449 .map(this::enhanceUser);
6450 }
6451
6452 // Stream API usage (modern feature)
6453 public List<User> getActiveUsers() {
6454 return repository.findAll().stream()
6455 .filter(User::isActive)
6456 .collect(Collectors.toList());
6457 }
6458
6459 private User enhanceUser(User user) {
6460 // Some enhancement logic
6461 return user;
6462 }
6463}
6464
6465// Security patterns
6466@PreAuthorize("hasRole('ADMIN')")
6467@RestController
6468public class UserController {
6469 @Autowired
6470 private UserService userService;
6471
6472 @GetMapping("/users/{id}")
6473 public ResponseEntity<User> getUser(@PathVariable Long id) {
6474 return userService.findUser(id)
6475 .map(ResponseEntity::ok)
6476 .orElse(ResponseEntity.notFound().build());
6477 }
6478}
6479"#;
6480
6481 let score = analyzer.calculate_overall_score(test_java_code);
6482
6483 assert_ne!(score, 75, "Score should not be the hardcoded value of 75");
6489 assert!(
6490 (50..=100).contains(&score),
6491 "Score should be in valid range 50-100, got {score}"
6492 );
6493
6494 let empty_score = analyzer.calculate_overall_score("");
6496 assert!(
6497 (0..=100).contains(&empty_score),
6498 "Empty code score should be in valid range"
6499 );
6500 assert_ne!(
6501 empty_score, score,
6502 "Empty code should have different score than good code"
6503 );
6504 }
6505
6506 #[test]
6507 fn test_calculate_overall_score_different_code_qualities() {
6508 let analyzer = JavaAnalyzer::new();
6509
6510 let good_code = r#"
6512public class GoodExample {
6513 private final String name;
6514
6515 public GoodExample(String name) {
6516 this.name = name;
6517 }
6518
6519 public Optional<String> getName() {
6520 return Optional.ofNullable(name);
6521 }
6522
6523 public List<String> processItems(List<String> items) {
6524 return items.stream()
6525 .filter(Objects::nonNull)
6526 .map(String::toUpperCase)
6527 .collect(Collectors.toList());
6528 }
6529}
6530"#;
6531
6532 let poor_code = r#"
6534public class PoorExample {
6535 public String name; // Public field - bad encapsulation
6536
6537 public String getName() {
6538 return name; // No null checking
6539 }
6540
6541 // Legacy patterns, no modern features
6542 public ArrayList getItems() {
6543 ArrayList list = new ArrayList();
6544 return list;
6545 }
6546}
6547"#;
6548
6549 let good_score = analyzer.calculate_overall_score(good_code);
6550 let poor_score = analyzer.calculate_overall_score(poor_code);
6551
6552 assert_ne!(good_score, 75, "Good code score should not be hardcoded 75");
6554 assert_ne!(poor_score, 75, "Poor code score should not be hardcoded 75");
6555
6556 assert!(
6558 (0..=100).contains(&good_score),
6559 "Good code score out of range: {good_score}"
6560 );
6561 assert!(
6562 (0..=100).contains(&poor_score),
6563 "Poor code score out of range: {poor_score}"
6564 );
6565
6566 println!("Good code score: {good_score}, Poor code score: {poor_score}");
6569 }
6570}