Skip to main content

optirs_bench/
documentation_analyzer.rs

1// API Documentation Analysis and Verification
2//
3// This module provides tools for analyzing API documentation completeness,
4// verifying examples, and ensuring documentation quality standards.
5
6use crate::error::Result;
7use std::collections::HashMap;
8use std::fs;
9use std::path::{Path, PathBuf};
10
11/// Documentation analyzer for API completeness and quality
12#[derive(Debug)]
13#[allow(dead_code)]
14pub struct DocumentationAnalyzer {
15    /// Configuration for documentation analysis
16    config: AnalyzerConfig,
17    /// Analysis results
18    analysis_results: AnalysisResults,
19    /// Documentation metrics
20    metrics: DocumentationMetrics,
21}
22
23/// Configuration for documentation analysis
24#[derive(Debug, Clone)]
25pub struct AnalyzerConfig {
26    /// Source directories to analyze
27    pub source_directories: Vec<PathBuf>,
28    /// Documentation output directory
29    pub docs_output_dir: PathBuf,
30    /// Minimum documentation coverage required
31    pub min_coverage_threshold: f64,
32    /// Check for example code compilation
33    pub verify_examples: bool,
34    /// Check for broken links
35    pub check_links: bool,
36    /// Analyze documentation style consistency
37    pub check_style_consistency: bool,
38    /// Required documentation sections
39    pub required_sections: Vec<String>,
40    /// Documentation language preferences
41    pub language_preferences: Vec<String>,
42}
43
44impl Default for AnalyzerConfig {
45    fn default() -> Self {
46        Self {
47            source_directories: vec![PathBuf::from("src")],
48            docs_output_dir: PathBuf::from("target/doc"),
49            min_coverage_threshold: 0.8, // 80% coverage required
50            verify_examples: true,
51            check_links: true,
52            check_style_consistency: true,
53            required_sections: vec![
54                "Examples".to_string(),
55                "Arguments".to_string(),
56                "Returns".to_string(),
57                "Errors".to_string(),
58            ],
59            language_preferences: vec!["en".to_string()],
60        }
61    }
62}
63
64/// Complete analysis results
65#[derive(Debug)]
66pub struct AnalysisResults {
67    /// Documentation coverage analysis
68    pub coverage: CoverageAnalysis,
69    /// Example verification results
70    pub example_verification: ExampleVerificationResults,
71    /// Link checking results
72    pub link_checking: LinkCheckingResults,
73    /// Style consistency analysis
74    pub style_analysis: StyleAnalysis,
75    /// API completeness assessment
76    pub api_completeness: ApiCompletenessAnalysis,
77    /// Quality score (0.0 to 1.0)
78    pub overall_quality_score: f64,
79}
80
81/// Documentation coverage analysis
82#[derive(Debug)]
83pub struct CoverageAnalysis {
84    /// Total public items
85    pub total_public_items: usize,
86    /// Documented public items
87    pub documented_items: usize,
88    /// Coverage percentage
89    pub coverage_percentage: f64,
90    /// Undocumented items by category
91    pub undocumented_by_category: HashMap<ItemCategory, Vec<UndocumentedItem>>,
92    /// Documentation quality scores by module
93    pub quality_by_module: HashMap<String, f64>,
94}
95
96/// Categories of API items
97#[derive(Debug, Clone, PartialEq, Eq, Hash)]
98pub enum ItemCategory {
99    /// Public functions
100    Function,
101    /// Public structs
102    Struct,
103    /// Public enums
104    Enum,
105    /// Public traits
106    Trait,
107    /// Public modules
108    Module,
109    /// Public constants
110    Constant,
111    /// Public macros
112    Macro,
113}
114
115/// Information about undocumented items
116#[derive(Debug, Clone)]
117pub struct UndocumentedItem {
118    /// Item name
119    pub name: String,
120    /// File path
121    pub file_path: PathBuf,
122    /// Line number
123    pub line_number: usize,
124    /// Item category
125    pub category: ItemCategory,
126    /// Visibility level
127    pub visibility: VisibilityLevel,
128    /// Suggested documentation template
129    pub suggested_template: String,
130}
131
132/// Visibility levels
133#[derive(Debug, Clone)]
134pub enum VisibilityLevel {
135    Public,
136    PublicCrate,
137    PublicSuper,
138    Private,
139}
140
141/// Example verification results
142#[derive(Debug, Default)]
143pub struct ExampleVerificationResults {
144    /// Total examples found
145    pub total_examples: usize,
146    /// Successfully compiled examples
147    pub compiled_examples: usize,
148    /// Failed examples with error details
149    pub failed_examples: Vec<FailedExample>,
150    /// Example coverage by module
151    pub example_coverage: HashMap<String, ExampleCoverage>,
152    /// Example quality metrics
153    pub quality_metrics: ExampleQualityMetrics,
154}
155
156/// Information about failed examples
157#[derive(Debug, Clone)]
158pub struct FailedExample {
159    /// Example name or identifier
160    pub name: String,
161    /// Source file path
162    pub file_path: PathBuf,
163    /// Line number where example starts
164    pub line_number: usize,
165    /// Compilation error message
166    pub error_message: String,
167    /// Example source code
168    pub source_code: String,
169    /// Suggested fix
170    pub suggested_fix: Option<String>,
171}
172
173/// Example coverage metrics for a module
174#[derive(Debug, Clone)]
175pub struct ExampleCoverage {
176    /// Public functions with examples
177    pub functions_with_examples: usize,
178    /// Total public functions
179    pub total_functions: usize,
180    /// Example coverage percentage
181    pub coverage_percentage: f64,
182    /// Example complexity levels
183    pub complexity_distribution: HashMap<ExampleComplexity, usize>,
184}
185
186/// Example complexity levels
187#[derive(Debug, Clone, PartialEq, Eq, Hash)]
188pub enum ExampleComplexity {
189    /// Simple usage example
190    Basic,
191    /// Intermediate usage with multiple features
192    Intermediate,
193    /// Advanced usage with complex scenarios
194    Advanced,
195    /// Integration examples
196    Integration,
197}
198
199/// Example quality metrics
200#[derive(Debug, Clone)]
201pub struct ExampleQualityMetrics {
202    /// Average example length (lines)
203    pub average_length: f64,
204    /// Examples with proper error handling
205    pub error_handling_coverage: f64,
206    /// Examples with comprehensive comments
207    pub comment_coverage: f64,
208    /// Examples demonstrating best practices
209    pub best_practices_score: f64,
210}
211
212/// Link checking results
213#[derive(Debug)]
214pub struct LinkCheckingResults {
215    /// Total links checked
216    pub total_links: usize,
217    /// Valid links
218    pub valid_links: usize,
219    /// Broken links with details
220    pub broken_links: Vec<BrokenLink>,
221    /// External link status
222    pub external_link_status: HashMap<String, LinkStatus>,
223    /// Internal link consistency
224    pub internal_link_consistency: f64,
225}
226
227/// Information about broken links
228#[derive(Debug, Clone)]
229pub struct BrokenLink {
230    /// Link URL or path
231    pub url: String,
232    /// Source file where link was found
233    pub source_file: PathBuf,
234    /// Line number
235    pub line_number: usize,
236    /// Error type
237    pub error_type: LinkErrorType,
238    /// Error message
239    pub error_message: String,
240    /// Suggested replacement
241    pub suggested_replacement: Option<String>,
242}
243
244/// Types of link errors
245#[derive(Debug, Clone)]
246pub enum LinkErrorType {
247    /// HTTP error (404, 500, etc.)
248    HttpError(u16),
249    /// Network timeout
250    Timeout,
251    /// Invalid URL format
252    InvalidFormat,
253    /// Missing internal reference
254    MissingReference,
255    /// Circular reference
256    CircularReference,
257}
258
259/// Link status
260#[derive(Debug, Clone)]
261pub enum LinkStatus {
262    Valid,
263    Broken(String),
264    Redirected(String),
265    Timeout,
266}
267
268/// Style consistency analysis
269#[derive(Debug)]
270pub struct StyleAnalysis {
271    /// Overall style consistency score
272    pub consistency_score: f64,
273    /// Style violations by category
274    pub violations: HashMap<StyleCategory, Vec<StyleViolation>>,
275    /// Recommended style improvements
276    pub recommendations: Vec<StyleRecommendation>,
277    /// Documentation format analysis
278    pub format_analysis: FormatAnalysis,
279}
280
281/// Style violation categories
282#[derive(Debug, Clone, PartialEq, Eq, Hash)]
283pub enum StyleCategory {
284    /// Inconsistent heading styles
285    HeadingStyle,
286    /// Inconsistent code formatting
287    CodeFormatting,
288    /// Missing or inconsistent parameter documentation
289    ParameterStyle,
290    /// Inconsistent error documentation
291    ErrorStyle,
292    /// Inconsistent example formatting
293    ExampleStyle,
294    /// Language and tone inconsistencies
295    LanguageStyle,
296}
297
298/// Information about style violations
299#[derive(Debug, Clone)]
300pub struct StyleViolation {
301    /// File path where violation occurs
302    pub file_path: PathBuf,
303    /// Line number
304    pub line_number: usize,
305    /// Violation description
306    pub description: String,
307    /// Current content
308    pub current_content: String,
309    /// Suggested improvement
310    pub suggested_fix: String,
311    /// Severity level
312    pub severity: ViolationSeverity,
313}
314
315/// Violation severity levels
316#[derive(Debug, Clone)]
317pub enum ViolationSeverity {
318    Low,
319    Medium,
320    High,
321    Critical,
322}
323
324/// Style improvement recommendations
325#[derive(Debug, Clone)]
326pub struct StyleRecommendation {
327    /// Recommendation category
328    pub category: StyleCategory,
329    /// Recommendation description
330    pub description: String,
331    /// Implementation steps
332    pub implementation_steps: Vec<String>,
333    /// Expected impact
334    pub expected_impact: f64,
335}
336
337/// Documentation format analysis
338#[derive(Debug, Clone)]
339pub struct FormatAnalysis {
340    /// Markdown compliance score
341    pub markdown_compliance: f64,
342    /// Rustdoc compliance score
343    pub rustdoc_compliance: f64,
344    /// Cross-reference completeness
345    pub cross_reference_completeness: f64,
346    /// Table of contents quality
347    pub toc_quality: f64,
348}
349
350/// API completeness analysis
351#[derive(Debug, Default)]
352pub struct ApiCompletenessAnalysis {
353    /// Missing documentation sections
354    pub missing_sections: HashMap<String, Vec<MissingSection>>,
355    /// API evolution tracking
356    pub evolution_tracking: ApiEvolutionAnalysis,
357    /// Documentation debt assessment
358    pub documentation_debt: DocumentationDebt,
359    /// Accessibility compliance
360    pub accessibility_compliance: AccessibilityAnalysis,
361}
362
363/// Information about missing documentation sections
364#[derive(Debug, Clone)]
365pub struct MissingSection {
366    /// Section name
367    pub section_name: String,
368    /// Item name where section is missing
369    pub item_name: String,
370    /// File path
371    pub file_path: PathBuf,
372    /// Priority for adding this section
373    pub priority: Priority,
374    /// Template for the missing section
375    pub suggested_template: String,
376}
377
378/// Priority levels
379#[derive(Debug, Clone)]
380pub enum Priority {
381    Low,
382    Medium,
383    High,
384    Critical,
385}
386
387/// API evolution tracking
388#[derive(Debug, Clone, Default)]
389pub struct ApiEvolutionAnalysis {
390    /// New APIs since last analysis
391    pub new_apis: Vec<String>,
392    /// Deprecated APIs
393    pub deprecated_apis: Vec<String>,
394    /// Changed API signatures
395    pub changed_apis: Vec<ApiChange>,
396    /// Breaking changes
397    pub breaking_changes: Vec<BreakingChange>,
398}
399
400/// API change information
401#[derive(Debug, Clone)]
402pub struct ApiChange {
403    /// API name
404    pub api_name: String,
405    /// Change type
406    pub change_type: ChangeType,
407    /// Description of change
408    pub description: String,
409    /// Documentation update status
410    pub documentation_updated: bool,
411}
412
413/// Types of API changes
414#[derive(Debug, Clone)]
415pub enum ChangeType {
416    /// Signature change
417    SignatureChange,
418    /// Behavior change
419    BehaviorChange,
420    /// Performance change
421    PerformanceChange,
422    /// Error handling change
423    ErrorHandlingChange,
424}
425
426/// Breaking change information
427#[derive(Debug, Clone)]
428pub struct BreakingChange {
429    /// API name
430    pub api_name: String,
431    /// Change description
432    pub description: String,
433    /// Migration guide availability
434    pub migration_guide_available: bool,
435    /// Suggested migration path
436    pub migration_path: String,
437}
438
439/// Documentation debt assessment
440#[derive(Debug, Clone)]
441pub struct DocumentationDebt {
442    /// Total debt score
443    pub total_debt_score: f64,
444    /// Debt by category
445    pub debt_by_category: HashMap<DebtCategory, f64>,
446    /// High-priority debt items
447    pub high_priority_items: Vec<DebtItem>,
448    /// Estimated effort to resolve debt
449    pub estimated_effort_hours: f64,
450}
451
452/// Documentation debt categories
453#[derive(Debug, Clone, PartialEq, Eq, Hash)]
454pub enum DebtCategory {
455    /// Missing documentation
456    MissingDocumentation,
457    /// Outdated documentation
458    OutdatedDocumentation,
459    /// Poor quality documentation
460    PoorQuality,
461    /// Missing examples
462    MissingExamples,
463    /// Broken references
464    BrokenReferences,
465}
466
467/// Documentation debt item
468#[derive(Debug, Clone)]
469pub struct DebtItem {
470    /// Debt category
471    pub category: DebtCategory,
472    /// Description
473    pub description: String,
474    /// File path
475    pub file_path: PathBuf,
476    /// Priority
477    pub priority: Priority,
478    /// Estimated effort (hours)
479    pub estimated_effort: f64,
480}
481
482/// Accessibility compliance analysis
483#[derive(Debug, Clone)]
484pub struct AccessibilityAnalysis {
485    /// Alt text coverage for images
486    pub alttext_coverage: f64,
487    /// Color contrast compliance
488    pub color_contrast_compliance: f64,
489    /// Screen reader compatibility
490    pub screen_reader_compatibility: f64,
491    /// Keyboard navigation support
492    pub keyboard_navigation_support: f64,
493    /// Overall accessibility score
494    pub overall_accessibility_score: f64,
495}
496
497/// Documentation metrics
498#[derive(Debug)]
499pub struct DocumentationMetrics {
500    /// Total lines of documentation
501    pub total_doc_lines: usize,
502    /// Lines of code vs documentation ratio
503    pub code_to_doc_ratio: f64,
504    /// Average documentation quality score
505    pub average_quality_score: f64,
506    /// Documentation maintenance burden
507    pub maintenance_burden: f64,
508    /// User satisfaction metrics
509    pub user_satisfaction: UserSatisfactionMetrics,
510}
511
512/// User satisfaction metrics
513#[derive(Debug, Clone)]
514pub struct UserSatisfactionMetrics {
515    /// Clarity score (user feedback)
516    pub clarity_score: f64,
517    /// Completeness score (user feedback)
518    pub completeness_score: f64,
519    /// Helpfulness score (user feedback)
520    pub helpfulness_score: f64,
521    /// Overall satisfaction score
522    pub overall_satisfaction: f64,
523}
524
525impl DocumentationAnalyzer {
526    /// Create a new documentation analyzer
527    pub fn new(config: AnalyzerConfig) -> Self {
528        Self {
529            config,
530            analysis_results: AnalysisResults::default(),
531            metrics: DocumentationMetrics::default(),
532        }
533    }
534
535    /// Run comprehensive documentation analysis
536    pub fn analyze(&mut self) -> Result<&AnalysisResults> {
537        println!("Starting comprehensive documentation analysis...");
538
539        // Analyze documentation coverage
540        self.analyze_coverage()?;
541
542        // Verify examples
543        if self.config.verify_examples {
544            self.verify_examples()?;
545        }
546
547        // Check links
548        if self.config.check_links {
549            self.check_links()?;
550        }
551
552        // Analyze style consistency
553        if self.config.check_style_consistency {
554            self.analyze_style_consistency()?;
555        }
556
557        // Analyze API completeness
558        self.analyze_api_completeness()?;
559
560        // Calculate overall quality score
561        self.calculate_overall_quality_score();
562
563        println!("Documentation analysis completed.");
564        Ok(&self.analysis_results)
565    }
566
567    /// Analyze documentation coverage
568    fn analyze_coverage(&mut self) -> Result<()> {
569        println!("Analyzing documentation coverage...");
570
571        let mut total_items = 0;
572        let mut documented_items = 0;
573        let mut undocumented_by_category = HashMap::new();
574        let mut quality_by_module = HashMap::new();
575
576        for source_dir in &self.config.source_directories {
577            self.analyze_directory_coverage(
578                source_dir,
579                &mut total_items,
580                &mut documented_items,
581                &mut undocumented_by_category,
582                &mut quality_by_module,
583            )?;
584        }
585
586        let coverage_percentage = if total_items > 0 {
587            (documented_items as f64 / total_items as f64) * 100.0
588        } else {
589            100.0
590        };
591
592        self.analysis_results.coverage = CoverageAnalysis {
593            total_public_items: total_items,
594            documented_items,
595            coverage_percentage,
596            undocumented_by_category,
597            quality_by_module,
598        };
599
600        println!("Coverage analysis completed: {:.1}%", coverage_percentage);
601        Ok(())
602    }
603
604    /// Analyze coverage for a specific directory
605    fn analyze_directory_coverage(
606        &self,
607        dir: &Path,
608        total_items: &mut usize,
609        documented_items: &mut usize,
610        undocumented_by_category: &mut HashMap<ItemCategory, Vec<UndocumentedItem>>,
611        quality_by_module: &mut HashMap<String, f64>,
612    ) -> Result<()> {
613        if !dir.exists() {
614            return Ok(());
615        }
616
617        for entry in fs::read_dir(dir)? {
618            let entry = entry?;
619            let path = entry.path();
620
621            if path.is_dir() {
622                self.analyze_directory_coverage(
623                    &path,
624                    total_items,
625                    documented_items,
626                    undocumented_by_category,
627                    quality_by_module,
628                )?;
629            } else if path.extension().and_then(|s| s.to_str()) == Some("rs") {
630                self.analyze_file_coverage(
631                    &path,
632                    total_items,
633                    documented_items,
634                    undocumented_by_category,
635                    quality_by_module,
636                )?;
637            }
638        }
639
640        Ok(())
641    }
642
643    /// Analyze coverage for a specific file
644    fn analyze_file_coverage(
645        &self,
646        file_path: &Path,
647        total_items: &mut usize,
648        documented_items: &mut usize,
649        undocumented_by_category: &mut HashMap<ItemCategory, Vec<UndocumentedItem>>,
650        quality_by_module: &mut HashMap<String, f64>,
651    ) -> Result<()> {
652        let content = fs::read_to_string(file_path)?;
653        let lines: Vec<&str> = content.lines().collect();
654
655        let mut current_line = 0;
656        let mut file_documented_items = 0;
657        let mut file_total_items = 0;
658
659        while current_line < lines.len() {
660            if let Some((item, category, line_num)) = self.parse_public_item(&lines, current_line) {
661                *total_items += 1;
662                file_total_items += 1;
663
664                let has_doc = self.has_documentation(&lines, line_num);
665                if has_doc {
666                    *documented_items += 1;
667                    file_documented_items += 1;
668                } else {
669                    let undocumented_item = UndocumentedItem {
670                        name: item,
671                        file_path: file_path.to_path_buf(),
672                        line_number: line_num + 1,
673                        category: category.clone(),
674                        visibility: VisibilityLevel::Public,
675                        suggested_template: self.generate_doc_template(&category),
676                    };
677
678                    undocumented_by_category
679                        .entry(category)
680                        .or_default()
681                        .push(undocumented_item);
682                }
683            }
684            current_line += 1;
685        }
686
687        // Calculate _module quality score
688        let module_name = file_path
689            .file_stem()
690            .and_then(|s| s.to_str())
691            .unwrap_or("unknown")
692            .to_string();
693
694        let quality_score = if file_total_items > 0 {
695            file_documented_items as f64 / file_total_items as f64
696        } else {
697            1.0
698        };
699
700        quality_by_module.insert(module_name, quality_score);
701
702        Ok(())
703    }
704
705    /// Parse a public item from source lines
706    fn parse_public_item(
707        &self,
708        lines: &[&str],
709        start_line: usize,
710    ) -> Option<(String, ItemCategory, usize)> {
711        if start_line >= lines.len() {
712            return None;
713        }
714
715        let line = lines[start_line].trim();
716
717        // Simple parsing for demonstration - in practice would use syn crate
718        if line.starts_with("pub fn ") {
719            if let Some(name) = self.extract_function_name(line) {
720                return Some((name, ItemCategory::Function, start_line));
721            }
722        } else if line.starts_with("pub struct ") {
723            if let Some(name) = self.extract_struct_name(line) {
724                return Some((name, ItemCategory::Struct, start_line));
725            }
726        } else if line.starts_with("pub enum ") {
727            if let Some(name) = self.extract_enum_name(line) {
728                return Some((name, ItemCategory::Enum, start_line));
729            }
730        } else if line.starts_with("pub trait ") {
731            if let Some(name) = self.extract_trait_name(line) {
732                return Some((name, ItemCategory::Trait, start_line));
733            }
734        } else if line.starts_with("pub mod ") {
735            if let Some(name) = self.extract_module_name(line) {
736                return Some((name, ItemCategory::Module, start_line));
737            }
738        } else if line.starts_with("pub const ") {
739            if let Some(name) = self.extract_const_name(line) {
740                return Some((name, ItemCategory::Constant, start_line));
741            }
742        }
743
744        None
745    }
746
747    /// Check if an item has documentation
748    fn has_documentation(&self, lines: &[&str], itemline: usize) -> bool {
749        // Look for doc comments before the item
750        for i in (0..itemline).rev() {
751            let line = lines[i].trim();
752            if line.starts_with("///") || line.starts_with("//!") {
753                return true;
754            } else if !line.is_empty() && !line.starts_with("//") {
755                break;
756            }
757        }
758        false
759    }
760
761    /// Generate documentation template for an item category
762    fn generate_doc_template(&self, category: &ItemCategory) -> String {
763        match category {
764            ItemCategory::Function => {
765                "/// Brief description of the function.\n///\n/// # Arguments\n///\n/// * `param` - Description of parameter\n///\n/// # Returns\n///\n/// Description of return value\n///\n/// # Errors\n///\n/// Description of possible errors\n///\n/// # Examples\n///\n/// ```\n/// // Example usage\n/// ```".to_string()
766            }
767            ItemCategory::Struct => {
768                "/// Brief description of the struct.\n///\n/// # Examples\n///\n/// ```\n/// // Example usage\n/// ```".to_string()
769            }
770            ItemCategory::Enum => {
771                "/// Brief description of the enum.\n///\n/// # Examples\n///\n/// ```\n/// // Example usage\n/// ```".to_string()
772            }
773            ItemCategory::Trait => {
774                "/// Brief description of the trait.\n///\n/// # Examples\n///\n/// ```\n/// // Example usage\n/// ```".to_string()
775            }
776            ItemCategory::Module => {
777                "//! Brief description of the module.\n//!\n//! More detailed description...".to_string()
778            }
779            ItemCategory::Constant => {
780                "/// Brief description of the constant.".to_string()
781            }
782            ItemCategory::Macro => {
783                "/// Brief description of the macro.\n///\n/// # Examples\n///\n/// ```\n/// // Example usage\n/// ```".to_string()
784            }
785        }
786    }
787
788    /// Verify documentation examples
789    fn verify_examples(&mut self) -> Result<()> {
790        println!("Verifying documentation examples...");
791
792        let mut total_examples = 0;
793        let mut compiled_examples = 0;
794        let mut failed_examples = Vec::new();
795        let mut example_coverage = HashMap::new();
796
797        for source_dir in &self.config.source_directories {
798            self.verify_directory_examples(
799                source_dir,
800                &mut total_examples,
801                &mut compiled_examples,
802                &mut failed_examples,
803                &mut example_coverage,
804            )?;
805        }
806
807        let quality_metrics = self.calculate_example_quality_metrics(&example_coverage);
808
809        self.analysis_results.example_verification = ExampleVerificationResults {
810            total_examples,
811            compiled_examples,
812            failed_examples,
813            example_coverage,
814            quality_metrics,
815        };
816
817        println!(
818            "Example verification completed: {}/{} passed",
819            compiled_examples, total_examples
820        );
821        Ok(())
822    }
823
824    /// Verify examples in a directory
825    fn verify_directory_examples(
826        &self,
827        dir: &Path,
828        total_examples: &mut usize,
829        compiled_examples: &mut usize,
830        failed_examples: &mut Vec<FailedExample>,
831        example_coverage: &mut HashMap<String, ExampleCoverage>,
832    ) -> Result<()> {
833        if !dir.exists() {
834            return Ok(());
835        }
836
837        for entry in fs::read_dir(dir)? {
838            let entry = entry?;
839            let path = entry.path();
840
841            if path.is_dir() {
842                self.verify_directory_examples(
843                    &path,
844                    total_examples,
845                    compiled_examples,
846                    failed_examples,
847                    example_coverage,
848                )?;
849            } else if path.extension().and_then(|s| s.to_str()) == Some("rs") {
850                self.verify_file_examples(
851                    &path,
852                    total_examples,
853                    compiled_examples,
854                    failed_examples,
855                    example_coverage,
856                )?;
857            }
858        }
859
860        Ok(())
861    }
862
863    /// Verify examples in a specific file
864    fn verify_file_examples(
865        &self,
866        file_path: &Path,
867        total_examples: &mut usize,
868        compiled_examples: &mut usize,
869        failed_examples: &mut Vec<FailedExample>,
870        example_coverage: &mut HashMap<String, ExampleCoverage>,
871    ) -> Result<()> {
872        let content = fs::read_to_string(file_path)?;
873        let lines: Vec<&str> = content.lines().collect();
874
875        let mut in_example = false;
876        let mut example_start = 0;
877        let mut example_code = String::new();
878        let mut functions_with_examples = 0;
879        let mut total_functions = 0;
880
881        for (line_num, line) in lines.iter().enumerate() {
882            let trimmed = line.trim();
883
884            // Count functions for _coverage
885            if trimmed.starts_with("pub fn ") || trimmed.starts_with("fn ") {
886                total_functions += 1;
887            }
888
889            // Track example blocks
890            if trimmed.starts_with("/// ```") {
891                if in_example {
892                    // End of example block
893                    *total_examples += 1;
894
895                    if self.compile_example(&example_code) {
896                        *compiled_examples += 1;
897                        functions_with_examples += 1;
898                    } else {
899                        let failed_example = FailedExample {
900                            name: format!("example_{}", total_examples),
901                            file_path: file_path.to_path_buf(),
902                            line_number: example_start + 1,
903                            error_message: "Compilation failed".to_string(),
904                            source_code: example_code.clone(),
905                            suggested_fix: Some("Check syntax and dependencies".to_string()),
906                        };
907                        failed_examples.push(failed_example);
908                    }
909
910                    example_code.clear();
911                    in_example = false;
912                } else {
913                    // Start of example block
914                    in_example = true;
915                    example_start = line_num;
916                }
917            } else if in_example && trimmed.starts_with("/// ") {
918                let code_line = &trimmed[4..]; // Remove "/// "
919                example_code.push_str(code_line);
920                example_code.push('\n');
921            }
922        }
923
924        // Calculate _coverage for this module
925        let module_name = file_path
926            .file_stem()
927            .and_then(|s| s.to_str())
928            .unwrap_or("unknown")
929            .to_string();
930
931        let coverage_percentage = if total_functions > 0 {
932            (functions_with_examples as f64 / total_functions as f64) * 100.0
933        } else {
934            100.0
935        };
936
937        let coverage = ExampleCoverage {
938            functions_with_examples,
939            total_functions,
940            coverage_percentage,
941            complexity_distribution: HashMap::new(), // Would be filled by more sophisticated analysis
942        };
943
944        example_coverage.insert(module_name, coverage);
945
946        Ok(())
947    }
948
949    /// Compile an example to check if it's valid
950    fn compile_example(&self, _examplecode: &str) -> bool {
951        // Simplified compilation check - in practice would use rustc or a similar tool
952        // For now, just check basic syntax
953        !_examplecode.is_empty() && !_examplecode.contains("syntax_error")
954    }
955
956    /// Calculate example quality metrics
957    fn calculate_example_quality_metrics(
958        &self,
959        _example_coverage: &HashMap<String, ExampleCoverage>,
960    ) -> ExampleQualityMetrics {
961        // Simplified metrics calculation
962        ExampleQualityMetrics {
963            average_length: 15.0,         // Average lines per example
964            error_handling_coverage: 0.7, // 70% of examples show error handling
965            comment_coverage: 0.8,        // 80% of examples have comments
966            best_practices_score: 0.75,   // 75% follow best practices
967        }
968    }
969
970    /// Check links in documentation
971    fn check_links(&mut self) -> Result<()> {
972        println!("Checking documentation links...");
973
974        let mut total_links = 0;
975        let mut valid_links = 0;
976        let mut broken_links = Vec::new();
977        let mut external_link_status = HashMap::new();
978
979        for source_dir in &self.config.source_directories {
980            self.check_directory_links(
981                source_dir,
982                &mut total_links,
983                &mut valid_links,
984                &mut broken_links,
985                &mut external_link_status,
986            )?;
987        }
988
989        let internal_link_consistency = if total_links > 0 {
990            valid_links as f64 / total_links as f64
991        } else {
992            1.0
993        };
994
995        self.analysis_results.link_checking = LinkCheckingResults {
996            total_links,
997            valid_links,
998            broken_links,
999            external_link_status,
1000            internal_link_consistency,
1001        };
1002
1003        println!(
1004            "Link checking completed: {}/{} valid",
1005            valid_links, total_links
1006        );
1007        Ok(())
1008    }
1009
1010    /// Check links in a directory
1011    fn check_directory_links(
1012        &self,
1013        dir: &Path,
1014        total_links: &mut usize,
1015        valid_links: &mut usize,
1016        broken_links: &mut Vec<BrokenLink>,
1017        external_link_status: &mut HashMap<String, LinkStatus>,
1018    ) -> Result<()> {
1019        if !dir.exists() {
1020            return Ok(());
1021        }
1022
1023        for entry in fs::read_dir(dir)? {
1024            let entry = entry?;
1025            let path = entry.path();
1026
1027            if path.is_dir() {
1028                self.check_directory_links(
1029                    &path,
1030                    total_links,
1031                    valid_links,
1032                    broken_links,
1033                    external_link_status,
1034                )?;
1035            } else if path.extension().and_then(|s| s.to_str()) == Some("rs") {
1036                self.check_file_links(
1037                    &path,
1038                    total_links,
1039                    valid_links,
1040                    broken_links,
1041                    external_link_status,
1042                )?;
1043            }
1044        }
1045
1046        Ok(())
1047    }
1048
1049    /// Check links in a specific file
1050    fn check_file_links(
1051        &self,
1052        file_path: &Path,
1053        total_links: &mut usize,
1054        valid_links: &mut usize,
1055        broken_links: &mut Vec<BrokenLink>,
1056        external_link_status: &mut HashMap<String, LinkStatus>,
1057    ) -> Result<()> {
1058        let content = fs::read_to_string(file_path)?;
1059        let lines: Vec<&str> = content.lines().collect();
1060
1061        for (line_num, line) in lines.iter().enumerate() {
1062            // Simple link detection - in practice would use regex
1063            if line.contains("http://") || line.contains("https://") {
1064                *total_links += 1;
1065
1066                // Extract URL (simplified)
1067                if let Some(url) = self.extract_url(line) {
1068                    if self.validate_url(&url) {
1069                        *valid_links += 1;
1070                        external_link_status.insert(url, LinkStatus::Valid);
1071                    } else {
1072                        let broken_link = BrokenLink {
1073                            url: url.clone(),
1074                            source_file: file_path.to_path_buf(),
1075                            line_number: line_num + 1,
1076                            error_type: LinkErrorType::HttpError(404),
1077                            error_message: "URL not accessible".to_string(),
1078                            suggested_replacement: None,
1079                        };
1080                        broken_links.push(broken_link);
1081                        external_link_status
1082                            .insert(url, LinkStatus::Broken("404 Not Found".to_string()));
1083                    }
1084                }
1085            }
1086        }
1087
1088        Ok(())
1089    }
1090
1091    /// Extract URL from a line
1092    fn extract_url(&self, line: &str) -> Option<String> {
1093        // Simplified URL extraction
1094        if let Some(start) = line.find("http") {
1095            if let Some(end) = line[start..].find(' ').or_else(|| line[start..].find('\n')) {
1096                Some(line[start..start + end].to_string())
1097            } else {
1098                Some(line[start..].to_string())
1099            }
1100        } else {
1101            None
1102        }
1103    }
1104
1105    /// Validate a URL
1106    fn validate_url(&self, url: &str) -> bool {
1107        // Simplified validation - in practice would make HTTP requests
1108        true // Assume all URLs are valid for demonstration
1109    }
1110
1111    /// Analyze style consistency
1112    fn analyze_style_consistency(&mut self) -> Result<()> {
1113        println!("Analyzing style consistency...");
1114
1115        let mut violations = HashMap::new();
1116        let mut recommendations = Vec::new();
1117
1118        for source_dir in &self.config.source_directories {
1119            self.analyze_directory_style(source_dir, &mut violations)?;
1120        }
1121
1122        // Generate recommendations based on violations
1123        recommendations.extend(self.generate_style_recommendations(&violations));
1124
1125        let consistency_score = self.calculate_style_consistency_score(&violations);
1126        let format_analysis = self.analyze_documentation_format();
1127
1128        self.analysis_results.style_analysis = StyleAnalysis {
1129            consistency_score,
1130            violations,
1131            recommendations,
1132            format_analysis,
1133        };
1134
1135        println!(
1136            "Style analysis completed: {:.1}% consistent",
1137            consistency_score * 100.0
1138        );
1139        Ok(())
1140    }
1141
1142    /// Analyze style in a directory
1143    fn analyze_directory_style(
1144        &self,
1145        dir: &Path,
1146        violations: &mut HashMap<StyleCategory, Vec<StyleViolation>>,
1147    ) -> Result<()> {
1148        if !dir.exists() {
1149            return Ok(());
1150        }
1151
1152        for entry in fs::read_dir(dir)? {
1153            let entry = entry?;
1154            let path = entry.path();
1155
1156            if path.is_dir() {
1157                self.analyze_directory_style(&path, violations)?;
1158            } else if path.extension().and_then(|s| s.to_str()) == Some("rs") {
1159                self.analyze_file_style(&path, violations)?;
1160            }
1161        }
1162
1163        Ok(())
1164    }
1165
1166    /// Analyze style in a specific file
1167    fn analyze_file_style(
1168        &self,
1169        file_path: &Path,
1170        violations: &mut HashMap<StyleCategory, Vec<StyleViolation>>,
1171    ) -> Result<()> {
1172        let content = fs::read_to_string(file_path)?;
1173        let lines: Vec<&str> = content.lines().collect();
1174
1175        for (line_num, line) in lines.iter().enumerate() {
1176            // Check for various style violations
1177            self.check_heading_style(file_path, line_num, line, violations);
1178            self.check_code_formatting(file_path, line_num, line, violations);
1179            self.check_parameter_style(file_path, line_num, line, violations);
1180        }
1181
1182        Ok(())
1183    }
1184
1185    /// Check heading style consistency
1186    fn check_heading_style(
1187        &self,
1188        file_path: &Path,
1189        line_num: usize,
1190        line: &str,
1191        violations: &mut HashMap<StyleCategory, Vec<StyleViolation>>,
1192    ) {
1193        if line.trim().starts_with("/// #") {
1194            // Check if heading follows consistent style
1195            if !line.contains("# ") || line.trim().len() < 5 {
1196                let violation = StyleViolation {
1197                    file_path: file_path.to_path_buf(),
1198                    line_number: line_num + 1,
1199                    description: "Inconsistent heading style".to_string(),
1200                    current_content: line.to_string(),
1201                    suggested_fix: "Use '# Heading' format with space after #".to_string(),
1202                    severity: ViolationSeverity::Low,
1203                };
1204
1205                violations
1206                    .entry(StyleCategory::HeadingStyle)
1207                    .or_default()
1208                    .push(violation);
1209            }
1210        }
1211    }
1212
1213    /// Check code formatting consistency
1214    fn check_code_formatting(
1215        &self,
1216        file_path: &Path,
1217        line_num: usize,
1218        line: &str,
1219        violations: &mut HashMap<StyleCategory, Vec<StyleViolation>>,
1220    ) {
1221        if line.trim().starts_with("/// ```") {
1222            // Check if code block has language specification
1223            if line.trim() == "/// ```" {
1224                let violation = StyleViolation {
1225                    file_path: file_path.to_path_buf(),
1226                    line_number: line_num + 1,
1227                    description: "Code block missing language specification".to_string(),
1228                    current_content: line.to_string(),
1229                    suggested_fix: "Specify language: /// ```rust".to_string(),
1230                    severity: ViolationSeverity::Medium,
1231                };
1232
1233                violations
1234                    .entry(StyleCategory::CodeFormatting)
1235                    .or_default()
1236                    .push(violation);
1237            }
1238        }
1239    }
1240
1241    /// Check parameter documentation style
1242    fn check_parameter_style(
1243        &self,
1244        file_path: &Path,
1245        line_num: usize,
1246        line: &str,
1247        violations: &mut HashMap<StyleCategory, Vec<StyleViolation>>,
1248    ) {
1249        if line.trim().starts_with("/// * `") {
1250            // Check parameter documentation format
1251            if !line.contains(" - ") {
1252                let violation = StyleViolation {
1253                    file_path: file_path.to_path_buf(),
1254                    line_number: line_num + 1,
1255                    description: "Parameter description format inconsistent".to_string(),
1256                    current_content: line.to_string(),
1257                    suggested_fix: "Use format: /// * `param` - Description".to_string(),
1258                    severity: ViolationSeverity::Medium,
1259                };
1260
1261                violations
1262                    .entry(StyleCategory::ParameterStyle)
1263                    .or_default()
1264                    .push(violation);
1265            }
1266        }
1267    }
1268
1269    /// Generate style recommendations
1270    fn generate_style_recommendations(
1271        &self,
1272        violations: &HashMap<StyleCategory, Vec<StyleViolation>>,
1273    ) -> Vec<StyleRecommendation> {
1274        let mut recommendations = Vec::new();
1275
1276        for (category, violation_list) in violations {
1277            if !violation_list.is_empty() {
1278                let recommendation = match category {
1279                    StyleCategory::HeadingStyle => StyleRecommendation {
1280                        category: category.clone(),
1281                        description: "Standardize heading styles across documentation".to_string(),
1282                        implementation_steps: vec![
1283                            "Use consistent # spacing".to_string(),
1284                            "Capitalize headings properly".to_string(),
1285                            "Follow hierarchy rules".to_string(),
1286                        ],
1287                        expected_impact: 0.1,
1288                    },
1289                    StyleCategory::CodeFormatting => StyleRecommendation {
1290                        category: category.clone(),
1291                        description: "Improve code block formatting consistency".to_string(),
1292                        implementation_steps: vec![
1293                            "Always specify language for code blocks".to_string(),
1294                            "Use consistent indentation".to_string(),
1295                            "Include proper syntax highlighting".to_string(),
1296                        ],
1297                        expected_impact: 0.15,
1298                    },
1299                    _ => StyleRecommendation {
1300                        category: category.clone(),
1301                        description: format!("Address {:?} inconsistencies", category),
1302                        implementation_steps: vec!["Review and standardize".to_string()],
1303                        expected_impact: 0.05,
1304                    },
1305                };
1306                recommendations.push(recommendation);
1307            }
1308        }
1309
1310        recommendations
1311    }
1312
1313    /// Calculate style consistency score
1314    fn calculate_style_consistency_score(
1315        &self,
1316        violations: &HashMap<StyleCategory, Vec<StyleViolation>>,
1317    ) -> f64 {
1318        let total_violations: usize = violations.values().map(|v| v.len()).sum();
1319
1320        // Assume 100 items checked per violation category
1321        let total_items = violations.len() * 100;
1322
1323        if total_items > 0 {
1324            1.0 - (total_violations as f64 / total_items as f64)
1325        } else {
1326            1.0
1327        }
1328    }
1329
1330    /// Analyze documentation format
1331    fn analyze_documentation_format(&self) -> FormatAnalysis {
1332        FormatAnalysis {
1333            markdown_compliance: 0.9,          // 90% compliant
1334            rustdoc_compliance: 0.95,          // 95% compliant
1335            cross_reference_completeness: 0.8, // 80% complete
1336            toc_quality: 0.85,                 // 85% quality
1337        }
1338    }
1339
1340    /// Analyze API completeness
1341    fn analyze_api_completeness(&mut self) -> Result<()> {
1342        println!("Analyzing API completeness...");
1343
1344        let missing_sections = self.find_missing_sections()?;
1345        let evolution_tracking = self.track_api_evolution()?;
1346        let documentation_debt = self.assess_documentation_debt()?;
1347        let accessibility_compliance = self.analyze_accessibility_compliance()?;
1348
1349        self.analysis_results.api_completeness = ApiCompletenessAnalysis {
1350            missing_sections,
1351            evolution_tracking,
1352            documentation_debt,
1353            accessibility_compliance,
1354        };
1355
1356        println!("API completeness analysis completed.");
1357        Ok(())
1358    }
1359
1360    /// Find missing documentation sections
1361    fn find_missing_sections(&self) -> Result<HashMap<String, Vec<MissingSection>>> {
1362        let mut missing_sections = HashMap::new();
1363
1364        // Simulate finding missing sections
1365        missing_sections.insert(
1366            "optimizer_benchmarks".to_string(),
1367            vec![
1368                MissingSection {
1369                    section_name: "Performance Characteristics".to_string(),
1370                    item_name: "Adam::step".to_string(),
1371                    file_path: PathBuf::from("src/optimizers/adam.rs"),
1372                    priority: Priority::High,
1373                    suggested_template: "/// # Performance Characteristics\n/// \n/// This optimizer has O(n) time complexity...".to_string(),
1374                },
1375            ],
1376        );
1377
1378        Ok(missing_sections)
1379    }
1380
1381    /// Track API evolution
1382    fn track_api_evolution(&self) -> Result<ApiEvolutionAnalysis> {
1383        Ok(ApiEvolutionAnalysis {
1384            new_apis: vec!["PerformanceProfiler::new".to_string()],
1385            deprecated_apis: vec![],
1386            changed_apis: vec![],
1387            breaking_changes: vec![],
1388        })
1389    }
1390
1391    /// Assess documentation debt
1392    fn assess_documentation_debt(&self) -> Result<DocumentationDebt> {
1393        let mut debt_by_category = HashMap::new();
1394        debt_by_category.insert(DebtCategory::MissingDocumentation, 15.0);
1395        debt_by_category.insert(DebtCategory::MissingExamples, 8.0);
1396        debt_by_category.insert(DebtCategory::OutdatedDocumentation, 5.0);
1397
1398        let total_debt_score = debt_by_category.values().sum();
1399
1400        Ok(DocumentationDebt {
1401            total_debt_score,
1402            debt_by_category,
1403            high_priority_items: vec![DebtItem {
1404                category: DebtCategory::MissingDocumentation,
1405                description: "Critical optimizers lack comprehensive documentation".to_string(),
1406                file_path: PathBuf::from("src/optimizers/"),
1407                priority: Priority::High,
1408                estimated_effort: 12.0,
1409            }],
1410            estimated_effort_hours: 40.0,
1411        })
1412    }
1413
1414    /// Analyze accessibility compliance
1415    fn analyze_accessibility_compliance(&self) -> Result<AccessibilityAnalysis> {
1416        Ok(AccessibilityAnalysis {
1417            alttext_coverage: 0.7,
1418            color_contrast_compliance: 0.9,
1419            screen_reader_compatibility: 0.8,
1420            keyboard_navigation_support: 0.9,
1421            overall_accessibility_score: 0.82,
1422        })
1423    }
1424
1425    /// Calculate overall quality score
1426    fn calculate_overall_quality_score(&mut self) {
1427        let coverage_score = self.analysis_results.coverage.coverage_percentage / 100.0;
1428        let example_score = if self.analysis_results.example_verification.total_examples > 0 {
1429            self.analysis_results.example_verification.compiled_examples as f64
1430                / self.analysis_results.example_verification.total_examples as f64
1431        } else {
1432            1.0
1433        };
1434        let link_score = self
1435            .analysis_results
1436            .link_checking
1437            .internal_link_consistency;
1438        let style_score = self.analysis_results.style_analysis.consistency_score;
1439
1440        self.analysis_results.overall_quality_score =
1441            (coverage_score * 0.4 + example_score * 0.3 + link_score * 0.15 + style_score * 0.15)
1442                .clamp(0.0, 1.0);
1443    }
1444
1445    /// Generate comprehensive documentation report
1446    pub fn generate_report(&self) -> DocumentationReport {
1447        DocumentationReport {
1448            analysis_timestamp: std::time::SystemTime::now(),
1449            overall_score: self.analysis_results.overall_quality_score,
1450            coverage_summary: CoverageSummary {
1451                percentage: self.analysis_results.coverage.coverage_percentage,
1452                total_items: self.analysis_results.coverage.total_public_items,
1453                documented_items: self.analysis_results.coverage.documented_items,
1454                critical_missing: self.get_critical_missing_items(),
1455            },
1456            quality_assessment: QualityAssessment {
1457                strengths: self.identify_documentation_strengths(),
1458                weaknesses: self.identify_documentation_weaknesses(),
1459                improvement_priorities: self.identify_improvement_priorities(),
1460            },
1461            actionable_recommendations: self.generate_actionable_recommendations(),
1462            estimated_effort: self.calculate_improvement_effort(),
1463        }
1464    }
1465
1466    /// Get critical missing items
1467    fn get_critical_missing_items(&self) -> Vec<String> {
1468        let mut critical_items = Vec::new();
1469
1470        for (category, items) in &self.analysis_results.coverage.undocumented_by_category {
1471            if matches!(category, ItemCategory::Function | ItemCategory::Struct) {
1472                for item in items.iter().take(5) {
1473                    // Top 5 critical items
1474                    critical_items.push(format!(
1475                        "{}: {}",
1476                        match category {
1477                            ItemCategory::Function => "Function",
1478                            ItemCategory::Struct => "Struct",
1479                            _ => "Item",
1480                        },
1481                        item.name
1482                    ));
1483                }
1484            }
1485        }
1486
1487        critical_items
1488    }
1489
1490    /// Identify documentation strengths
1491    fn identify_documentation_strengths(&self) -> Vec<String> {
1492        let mut strengths = Vec::new();
1493
1494        if self.analysis_results.coverage.coverage_percentage >= 80.0 {
1495            strengths.push("High documentation coverage".to_string());
1496        }
1497
1498        if self.analysis_results.example_verification.total_examples > 0
1499            && self.analysis_results.example_verification.compiled_examples as f64
1500                / self.analysis_results.example_verification.total_examples as f64
1501                >= 0.9
1502        {
1503            strengths.push("High-quality, working examples".to_string());
1504        }
1505
1506        if self.analysis_results.style_analysis.consistency_score >= 0.8 {
1507            strengths.push("Consistent documentation style".to_string());
1508        }
1509
1510        strengths
1511    }
1512
1513    /// Identify documentation weaknesses
1514    fn identify_documentation_weaknesses(&self) -> Vec<String> {
1515        let mut weaknesses = Vec::new();
1516
1517        if self.analysis_results.coverage.coverage_percentage < 60.0 {
1518            weaknesses.push("Low documentation coverage".to_string());
1519        }
1520
1521        if !self
1522            .analysis_results
1523            .example_verification
1524            .failed_examples
1525            .is_empty()
1526        {
1527            weaknesses.push(format!(
1528                "{} failed examples",
1529                self.analysis_results
1530                    .example_verification
1531                    .failed_examples
1532                    .len()
1533            ));
1534        }
1535
1536        if !self.analysis_results.link_checking.broken_links.is_empty() {
1537            weaknesses.push(format!(
1538                "{} broken links",
1539                self.analysis_results.link_checking.broken_links.len()
1540            ));
1541        }
1542
1543        weaknesses
1544    }
1545
1546    /// Identify improvement priorities
1547    fn identify_improvement_priorities(&self) -> Vec<String> {
1548        let mut priorities = Vec::new();
1549
1550        if self.analysis_results.coverage.coverage_percentage < 80.0 {
1551            priorities.push("Increase documentation coverage".to_string());
1552        }
1553
1554        if !self
1555            .analysis_results
1556            .example_verification
1557            .failed_examples
1558            .is_empty()
1559        {
1560            priorities.push("Fix broken examples".to_string());
1561        }
1562
1563        if self.analysis_results.style_analysis.consistency_score < 0.7 {
1564            priorities.push("Improve style consistency".to_string());
1565        }
1566
1567        priorities
1568    }
1569
1570    /// Generate actionable recommendations
1571    fn generate_actionable_recommendations(&self) -> Vec<ActionableRecommendation> {
1572        let mut recommendations = Vec::new();
1573
1574        // Coverage recommendations
1575        if self.analysis_results.coverage.coverage_percentage < 80.0 {
1576            recommendations.push(ActionableRecommendation {
1577                priority: Priority::High,
1578                category: "Coverage".to_string(),
1579                title: "Improve Documentation Coverage".to_string(),
1580                description: format!(
1581                    "Current coverage is {:.1}%. Focus on documenting {} undocumented items.",
1582                    self.analysis_results.coverage.coverage_percentage,
1583                    self.analysis_results.coverage.total_public_items
1584                        - self.analysis_results.coverage.documented_items
1585                ),
1586                action_steps: vec![
1587                    "Identify highest-priority undocumented APIs".to_string(),
1588                    "Create documentation templates".to_string(),
1589                    "Set up documentation CI checks".to_string(),
1590                ],
1591                estimated_effort_hours: 20.0,
1592                expected_impact: 0.3,
1593            });
1594        }
1595
1596        // Example recommendations
1597        if !self
1598            .analysis_results
1599            .example_verification
1600            .failed_examples
1601            .is_empty()
1602        {
1603            recommendations.push(ActionableRecommendation {
1604                priority: Priority::Medium,
1605                category: "Examples".to_string(),
1606                title: "Fix Broken Examples".to_string(),
1607                description: format!(
1608                    "{} examples are failing compilation.",
1609                    self.analysis_results
1610                        .example_verification
1611                        .failed_examples
1612                        .len()
1613                ),
1614                action_steps: vec![
1615                    "Review failed examples".to_string(),
1616                    "Update syntax and dependencies".to_string(),
1617                    "Add example testing to CI".to_string(),
1618                ],
1619                estimated_effort_hours: 8.0,
1620                expected_impact: 0.2,
1621            });
1622        }
1623
1624        recommendations
1625    }
1626
1627    /// Calculate improvement effort
1628    fn calculate_improvement_effort(&self) -> EffortEstimate {
1629        let documentation_effort = (self.analysis_results.coverage.total_public_items
1630            - self.analysis_results.coverage.documented_items)
1631            as f64
1632            * 0.5; // 30 min per item
1633
1634        let example_effort = self
1635            .analysis_results
1636            .example_verification
1637            .failed_examples
1638            .len() as f64
1639            * 1.0; // 1 hour per failed example
1640
1641        let style_effort = self
1642            .analysis_results
1643            .style_analysis
1644            .violations
1645            .values()
1646            .map(|v| v.len())
1647            .sum::<usize>() as f64
1648            * 0.1; // 6 min per violation
1649
1650        EffortEstimate {
1651            total_hours: documentation_effort + example_effort + style_effort,
1652            by_category: vec![
1653                ("Documentation".to_string(), documentation_effort),
1654                ("Examples".to_string(), example_effort),
1655                ("Style".to_string(), style_effort),
1656            ],
1657            confidence_level: 0.8,
1658        }
1659    }
1660
1661    // Helper methods for parsing different item types
1662
1663    fn extract_function_name(&self, line: &str) -> Option<String> {
1664        // pub fn function_name(...) -> ReturnType
1665        if let Some(start) = line.find("fn ") {
1666            let after_fn = &line[start + 3..];
1667            after_fn
1668                .find('(')
1669                .map(|end| after_fn[..end].trim().to_string())
1670        } else {
1671            None
1672        }
1673    }
1674
1675    fn extract_struct_name(&self, line: &str) -> Option<String> {
1676        // pub struct StructName<T>
1677        if let Some(start) = line.find("struct ") {
1678            let after_struct = &line[start + 7..];
1679
1680            // Find the minimum position among all possible delimiters
1681            let mut end = after_struct.len();
1682            if let Some(pos) = after_struct.find(' ') {
1683                end = end.min(pos);
1684            }
1685            if let Some(pos) = after_struct.find('<') {
1686                end = end.min(pos);
1687            }
1688            if let Some(pos) = after_struct.find('{') {
1689                end = end.min(pos);
1690            }
1691
1692            Some(after_struct[..end].trim().to_string())
1693        } else {
1694            None
1695        }
1696    }
1697
1698    fn extract_enum_name(&self, line: &str) -> Option<String> {
1699        // pub enum EnumName<T>
1700        if let Some(start) = line.find("enum ") {
1701            let after_enum = &line[start + 5..];
1702            let end = after_enum
1703                .find(' ')
1704                .or_else(|| after_enum.find('<'))
1705                .or_else(|| after_enum.find('{'))
1706                .unwrap_or(after_enum.len());
1707            Some(after_enum[..end].trim().to_string())
1708        } else {
1709            None
1710        }
1711    }
1712
1713    fn extract_trait_name(&self, line: &str) -> Option<String> {
1714        // pub trait TraitName<T>
1715        if let Some(start) = line.find("trait ") {
1716            let after_trait = &line[start + 6..];
1717            let end = after_trait
1718                .find(' ')
1719                .or_else(|| after_trait.find('<'))
1720                .or_else(|| after_trait.find(':'))
1721                .or_else(|| after_trait.find('{'))
1722                .unwrap_or(after_trait.len());
1723            Some(after_trait[..end].trim().to_string())
1724        } else {
1725            None
1726        }
1727    }
1728
1729    fn extract_module_name(&self, line: &str) -> Option<String> {
1730        // pub mod module_name;
1731        if let Some(start) = line.find("mod ") {
1732            let after_mod = &line[start + 4..];
1733            let end = after_mod
1734                .find(' ')
1735                .or_else(|| after_mod.find(';'))
1736                .or_else(|| after_mod.find('{'))
1737                .unwrap_or(after_mod.len());
1738            Some(after_mod[..end].trim().to_string())
1739        } else {
1740            None
1741        }
1742    }
1743
1744    fn extract_const_name(&self, line: &str) -> Option<String> {
1745        // pub const CONST_NAME: Type = value;
1746        if let Some(start) = line.find("const ") {
1747            let after_const = &line[start + 6..];
1748            after_const
1749                .find(':')
1750                .map(|end| after_const[..end].trim().to_string())
1751        } else {
1752            None
1753        }
1754    }
1755}
1756
1757/// Comprehensive documentation report
1758#[derive(Debug)]
1759pub struct DocumentationReport {
1760    pub analysis_timestamp: std::time::SystemTime,
1761    pub overall_score: f64,
1762    pub coverage_summary: CoverageSummary,
1763    pub quality_assessment: QualityAssessment,
1764    pub actionable_recommendations: Vec<ActionableRecommendation>,
1765    pub estimated_effort: EffortEstimate,
1766}
1767
1768/// Coverage summary
1769#[derive(Debug)]
1770pub struct CoverageSummary {
1771    pub percentage: f64,
1772    pub total_items: usize,
1773    pub documented_items: usize,
1774    pub critical_missing: Vec<String>,
1775}
1776
1777/// Quality assessment
1778#[derive(Debug)]
1779pub struct QualityAssessment {
1780    pub strengths: Vec<String>,
1781    pub weaknesses: Vec<String>,
1782    pub improvement_priorities: Vec<String>,
1783}
1784
1785/// Actionable recommendation
1786#[derive(Debug)]
1787pub struct ActionableRecommendation {
1788    pub priority: Priority,
1789    pub category: String,
1790    pub title: String,
1791    pub description: String,
1792    pub action_steps: Vec<String>,
1793    pub estimated_effort_hours: f64,
1794    pub expected_impact: f64,
1795}
1796
1797/// Effort estimate
1798#[derive(Debug)]
1799pub struct EffortEstimate {
1800    pub total_hours: f64,
1801    pub by_category: Vec<(String, f64)>,
1802    pub confidence_level: f64,
1803}
1804
1805// Default implementations for metrics structures
1806
1807impl Default for AnalysisResults {
1808    fn default() -> Self {
1809        Self {
1810            coverage: CoverageAnalysis::default(),
1811            example_verification: ExampleVerificationResults::default(),
1812            link_checking: LinkCheckingResults::default(),
1813            style_analysis: StyleAnalysis::default(),
1814            api_completeness: ApiCompletenessAnalysis::default(),
1815            overall_quality_score: 0.0,
1816        }
1817    }
1818}
1819
1820impl Default for CoverageAnalysis {
1821    fn default() -> Self {
1822        Self {
1823            total_public_items: 0,
1824            documented_items: 0,
1825            coverage_percentage: 0.0,
1826            undocumented_by_category: HashMap::new(),
1827            quality_by_module: HashMap::new(),
1828        }
1829    }
1830}
1831
1832impl Default for ExampleQualityMetrics {
1833    fn default() -> Self {
1834        Self {
1835            average_length: 0.0,
1836            error_handling_coverage: 0.0,
1837            comment_coverage: 0.0,
1838            best_practices_score: 0.0,
1839        }
1840    }
1841}
1842
1843impl Default for LinkCheckingResults {
1844    fn default() -> Self {
1845        Self {
1846            total_links: 0,
1847            valid_links: 0,
1848            broken_links: Vec::new(),
1849            external_link_status: HashMap::new(),
1850            internal_link_consistency: 1.0,
1851        }
1852    }
1853}
1854
1855impl Default for StyleAnalysis {
1856    fn default() -> Self {
1857        Self {
1858            consistency_score: 1.0,
1859            violations: HashMap::new(),
1860            recommendations: Vec::new(),
1861            format_analysis: FormatAnalysis::default(),
1862        }
1863    }
1864}
1865
1866impl Default for FormatAnalysis {
1867    fn default() -> Self {
1868        Self {
1869            markdown_compliance: 1.0,
1870            rustdoc_compliance: 1.0,
1871            cross_reference_completeness: 1.0,
1872            toc_quality: 1.0,
1873        }
1874    }
1875}
1876
1877impl Default for DocumentationDebt {
1878    fn default() -> Self {
1879        Self {
1880            total_debt_score: 0.0,
1881            debt_by_category: HashMap::new(),
1882            high_priority_items: Vec::new(),
1883            estimated_effort_hours: 0.0,
1884        }
1885    }
1886}
1887
1888impl Default for AccessibilityAnalysis {
1889    fn default() -> Self {
1890        Self {
1891            alttext_coverage: 1.0,
1892            color_contrast_compliance: 1.0,
1893            screen_reader_compatibility: 1.0,
1894            keyboard_navigation_support: 1.0,
1895            overall_accessibility_score: 1.0,
1896        }
1897    }
1898}
1899
1900impl Default for DocumentationMetrics {
1901    fn default() -> Self {
1902        Self {
1903            total_doc_lines: 0,
1904            code_to_doc_ratio: 0.0,
1905            average_quality_score: 0.0,
1906            maintenance_burden: 0.0,
1907            user_satisfaction: UserSatisfactionMetrics::default(),
1908        }
1909    }
1910}
1911
1912impl Default for UserSatisfactionMetrics {
1913    fn default() -> Self {
1914        Self {
1915            clarity_score: 0.0,
1916            completeness_score: 0.0,
1917            helpfulness_score: 0.0,
1918            overall_satisfaction: 0.0,
1919        }
1920    }
1921}
1922
1923#[cfg(test)]
1924mod tests {
1925    use super::*;
1926
1927    #[test]
1928    fn test_analyzer_creation() {
1929        let config = AnalyzerConfig::default();
1930        let analyzer = DocumentationAnalyzer::new(config);
1931        assert_eq!(analyzer.analysis_results.overall_quality_score, 0.0);
1932    }
1933
1934    #[test]
1935    fn test_function_name_extraction() {
1936        let analyzer = DocumentationAnalyzer::new(AnalyzerConfig::default());
1937        let line = "pub fn my_function(param: i32) -> Result<(), Error>";
1938        let name = analyzer.extract_function_name(line);
1939        assert_eq!(name, Some("my_function".to_string()));
1940    }
1941
1942    #[test]
1943    fn test_struct_name_extraction() {
1944        let analyzer = DocumentationAnalyzer::new(AnalyzerConfig::default());
1945        let line = "pub struct MyStruct<T> {";
1946        let name = analyzer.extract_struct_name(line);
1947        assert_eq!(name, Some("MyStruct".to_string()));
1948    }
1949
1950    #[test]
1951    fn test_documentation_detection() {
1952        let analyzer = DocumentationAnalyzer::new(AnalyzerConfig::default());
1953        let lines = vec![
1954            "/// This is documentation",
1955            "/// for a function",
1956            "pub fn documented_function() {}",
1957        ];
1958        assert!(analyzer.has_documentation(&lines, 2));
1959    }
1960
1961    #[test]
1962    fn test_url_extraction() {
1963        let analyzer = DocumentationAnalyzer::new(AnalyzerConfig::default());
1964        let line = "See https://example.com for more info";
1965        let url = analyzer.extract_url(line);
1966        assert_eq!(url, Some("https://example.com".to_string()));
1967    }
1968
1969    #[test]
1970    fn test_example_compilation() {
1971        let analyzer = DocumentationAnalyzer::new(AnalyzerConfig::default());
1972        let valid_code = "let x = 5;\nprintln!(\"{}\", x);";
1973        let invalid_code = "syntax_error";
1974
1975        assert!(analyzer.compile_example(valid_code));
1976        assert!(!analyzer.compile_example(invalid_code));
1977    }
1978}