semantic/diff/diff_types.rs
1// SPDX-License-Identifier: Apache-2.0
2//! Shared semantic diff result and budget types.
3
4use std::path::PathBuf;
5
6use objects::object::{FileChangeSet, SemanticChange};
7
8use crate::analysis::AggregationResult;
9
10/// Resource limits used by semantic analysis.
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct SemanticBudget {
13 /// Maximum number of changed files to analyze semantically.
14 pub max_changed_files: usize,
15 /// Maximum total bytes to load across changed files.
16 pub max_total_bytes: usize,
17 /// Maximum number of files that may be parsed structurally.
18 pub max_parsed_files: usize,
19 /// Maximum file size eligible for parsing.
20 pub max_file_bytes: usize,
21}
22
23impl SemanticBudget {
24 /// Returns a budget with no practical limits.
25 pub fn unlimited() -> Self {
26 Self {
27 max_changed_files: usize::MAX,
28 max_total_bytes: usize::MAX,
29 max_parsed_files: usize::MAX,
30 max_file_bytes: usize::MAX,
31 }
32 }
33}
34
35impl Default for SemanticBudget {
36 fn default() -> Self {
37 Self {
38 max_changed_files: 2_048,
39 max_total_bytes: 16 * 1024 * 1024,
40 max_parsed_files: 512,
41 max_file_bytes: 1024 * 1024,
42 }
43 }
44}
45
46/// Conservative reason that semantic analysis skipped or degraded work.
47#[derive(Clone, Debug, PartialEq, Eq)]
48pub enum SemanticFallbackReason {
49 /// The changed-file set exceeded the configured limit.
50 ChangedFileBudgetExceeded { limit: usize, actual: usize },
51 /// Loaded content exceeded the configured byte budget.
52 TotalByteBudgetExceeded { limit: usize, actual: usize },
53 /// A file was too large for structural parsing.
54 FileTooLarge {
55 path: PathBuf,
56 limit: usize,
57 actual: usize,
58 },
59 /// Structural parsing hit the configured file-count budget.
60 ParseBudgetExceeded { limit: usize, attempted: usize },
61 /// The file language is unsupported for structural parsing.
62 UnsupportedLanguage { path: PathBuf },
63 /// Tree-sitter failed to produce a clean parse.
64 ParseFailed { path: PathBuf },
65}
66
67/// Result classification for the cheap semantic check path.
68#[derive(Clone, Copy, Debug, PartialEq, Eq)]
69pub enum SemanticCheckStatus {
70 /// The requested change-set is semantically empty.
71 NoChanges,
72 /// The requested change-set definitely contains changes.
73 HasChanges,
74 /// The fast path could not complete within the configured budget.
75 Fallback,
76}
77
78/// Result of the cheap semantic no-op check.
79#[derive(Clone, Debug)]
80pub struct SemanticCheckOnlyResult {
81 /// Final status of the fast path.
82 pub status: SemanticCheckStatus,
83 /// Raw file changes considered by the engine.
84 pub file_changes: FileChangeSet,
85 /// Explicit reasons why the fast path degraded.
86 pub fallback_reasons: Vec<SemanticFallbackReason>,
87}
88
89/// Aggregated semantic summary without the full detailed change list.
90#[derive(Clone, Debug, Default)]
91pub struct SemanticSummaryResult {
92 /// Files that were classified as renames.
93 pub file_renames: Vec<(PathBuf, PathBuf)>,
94 /// Raw file-level changes.
95 pub file_changes: FileChangeSet,
96 /// Aggregated semantic groups.
97 pub aggregated: Option<AggregationResult>,
98 /// Explicit reasons why parts of semantic analysis degraded.
99 pub fallback_reasons: Vec<SemanticFallbackReason>,
100}
101
102/// Result of full semantic diff analysis.
103#[derive(Clone, Debug, Default)]
104pub struct SemanticDiffResult {
105 /// High-level semantic changes detected.
106 pub changes: Vec<SemanticChange>,
107 /// Files that were renamed (old -> new).
108 pub file_renames: Vec<(PathBuf, PathBuf)>,
109 /// Raw file-level changes.
110 pub file_changes: FileChangeSet,
111 /// Aggregated changes (groups formatting passes, cross-file renames, etc.)
112 pub aggregated: Option<AggregationResult>,
113 /// Explicit reasons why parts of semantic analysis degraded.
114 pub fallback_reasons: Vec<SemanticFallbackReason>,
115}