Skip to content

Commit ea42495

Browse files
committed
fix: scope refactor generation before planning fixes
1 parent 7ecbfd9 commit ea42495

5 files changed

Lines changed: 105 additions & 59 deletions

File tree

src/core/code_audit/report.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,11 @@ pub fn compute_fixability(result: &CodeAuditResult) -> Option<AuditFixability> {
176176
}
177177

178178
// Generate fix plan (dry-run — never writes)
179-
let mut fix_result = crate::refactor::plan::generate::generate_audit_fixes(result, source_path);
179+
let mut fix_result = crate::refactor::plan::generate::generate_audit_fixes(
180+
result,
181+
source_path,
182+
&crate::refactor::auto::FixPolicy::default(),
183+
);
180184

181185
if fix_result.fixes.is_empty() && fix_result.new_files.is_empty() {
182186
return None;

src/core/refactor/add.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub fn fixes_from_audit(audit: &CodeAuditResult, write: bool) -> Result<FixResul
4848
));
4949
}
5050

51-
let mut fix_result = plan::generate_audit_fixes(audit, root);
51+
let mut fix_result = plan::generate_audit_fixes(audit, root, &auto::FixPolicy::default());
5252

5353
if write && !fix_result.fixes.is_empty() {
5454
let applied = auto::apply_fixes(&mut fix_result.fixes, root);

src/core/refactor/plan/generate/mod.rs

Lines changed: 94 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ mod signatures;
1212
mod test_gen_fixes;
1313

1414
use crate::code_audit::{AuditFinding, CodeAuditResult};
15-
use crate::core::refactor::auto::{DecomposeFixPlan, Fix, FixResult, SkippedFile};
15+
use crate::core::refactor::auto::{DecomposeFixPlan, Fix, FixPolicy, FixResult, SkippedFile};
1616
use crate::core::refactor::decompose;
1717
use crate::core::refactor::plan::file_intent::{FileIntent, FileIntentMap};
1818
use std::path::Path;
@@ -30,8 +30,8 @@ pub(crate) use signatures::{
3030
primary_type_name_from_declaration,
3131
};
3232

33-
pub fn generate_audit_fixes(result: &CodeAuditResult, root: &Path) -> FixResult {
34-
generate_fixes_impl(result, root)
33+
pub fn generate_audit_fixes(result: &CodeAuditResult, root: &Path, policy: &FixPolicy) -> FixResult {
34+
generate_fixes_impl(result, root, policy)
3535
}
3636

3737
pub(crate) fn merge_fixes_per_file(fixes: Vec<Fix>) -> Vec<Fix> {
@@ -63,9 +63,16 @@ pub(crate) fn merge_fixes_per_file(fixes: Vec<Fix>) -> Vec<Fix> {
6363
.collect()
6464
}
6565

66-
pub(crate) fn generate_fixes_impl(result: &CodeAuditResult, root: &Path) -> FixResult {
66+
pub(crate) fn generate_fixes_impl(result: &CodeAuditResult, root: &Path, policy: &FixPolicy) -> FixResult {
6767
let mut fixes = Vec::new();
6868
let mut skipped = Vec::new();
69+
let finding_enabled = |finding: &AuditFinding| {
70+
policy
71+
.only
72+
.as_ref()
73+
.is_none_or(|only| only.contains(finding))
74+
&& !policy.exclude.contains(finding)
75+
};
6976

7077
// ── Phase 0: Build file intent map ─────────────────────────────────
7178
// Identify structural operations (decompose, move, delete) planned for
@@ -75,6 +82,9 @@ pub(crate) fn generate_fixes_impl(result: &CodeAuditResult, root: &Path) -> FixR
7582
// declarative conflict rules.
7683
let mut intent_map = FileIntentMap::new();
7784
for finding in &result.findings {
85+
if !finding_enabled(&finding.kind) {
86+
continue;
87+
}
7888
if matches!(
7989
finding.kind,
8090
AuditFinding::GodFile | AuditFinding::HighItemCount
@@ -87,68 +97,100 @@ pub(crate) fn generate_fixes_impl(result: &CodeAuditResult, root: &Path) -> FixR
8797
// ── Phase 1: Generate all content fixes ────────────────────────────
8898
// Fixers run freely against the audit data. Conflicts with structural
8999
// intents are resolved after generation, not during.
90-
apply_convention_fixes(result, root, &mut fixes, &mut skipped);
100+
if policy.only.is_none() && policy.exclude.is_empty() {
101+
apply_convention_fixes(result, root, &mut fixes, &mut skipped);
102+
}
91103

92104
let mut new_files = Vec::new();
93-
generate_unreferenced_export_fixes(result, root, &mut fixes, &mut skipped);
94-
generate_duplicate_function_fixes(result, root, &mut fixes, &mut new_files, &mut skipped);
95-
orphaned_test_fixes::generate_orphaned_test_fixes(result, root, &mut fixes, &mut skipped);
105+
if finding_enabled(&AuditFinding::UnreferencedExport) {
106+
generate_unreferenced_export_fixes(result, root, &mut fixes, &mut skipped);
107+
}
108+
if finding_enabled(&AuditFinding::DuplicateFunction) {
109+
generate_duplicate_function_fixes(result, root, &mut fixes, &mut new_files, &mut skipped);
110+
}
111+
if finding_enabled(&AuditFinding::OrphanedTest) {
112+
orphaned_test_fixes::generate_orphaned_test_fixes(result, root, &mut fixes, &mut skipped);
113+
}
96114

97115
// ── Phase 2: Build decompose plans ─────────────────────────────────
98116
let mut decompose_plans = Vec::new();
99117
let mut decompose_seen = std::collections::HashSet::new();
100-
for finding in &result.findings {
101-
if !matches!(
102-
finding.kind,
103-
AuditFinding::GodFile | AuditFinding::HighItemCount
104-
) {
105-
continue;
106-
}
107-
// A file can trigger both GodFile and HighItemCount — only plan once.
108-
if decompose_seen.contains(&finding.file) {
109-
continue;
110-
}
111-
let is_test = crate::code_audit::walker::is_test_path(&finding.file);
112-
if is_test {
113-
continue;
114-
}
115-
match decompose::build_plan(&finding.file, root, "grouped") {
116-
Ok(plan) => {
117-
if plan.groups.len() > 1 {
118+
if finding_enabled(&AuditFinding::GodFile) || finding_enabled(&AuditFinding::HighItemCount) {
119+
for finding in &result.findings {
120+
if !finding_enabled(&finding.kind) {
121+
continue;
122+
}
123+
if !matches!(
124+
finding.kind,
125+
AuditFinding::GodFile | AuditFinding::HighItemCount
126+
) {
127+
continue;
128+
}
129+
if decompose_seen.contains(&finding.file) {
130+
continue;
131+
}
132+
let is_test = crate::code_audit::walker::is_test_path(&finding.file);
133+
if is_test {
134+
continue;
135+
}
136+
match decompose::build_plan(&finding.file, root, "grouped") {
137+
Ok(plan) => {
138+
if plan.groups.len() > 1 {
139+
decompose_seen.insert(finding.file.clone());
140+
decompose_plans.push(DecomposeFixPlan {
141+
file: finding.file.clone(),
142+
plan,
143+
source_finding: finding.kind.clone(),
144+
applied: false,
145+
});
146+
}
147+
}
148+
Err(error) => {
118149
decompose_seen.insert(finding.file.clone());
119-
decompose_plans.push(DecomposeFixPlan {
150+
skipped.push(SkippedFile {
120151
file: finding.file.clone(),
121-
plan,
122-
source_finding: finding.kind.clone(),
123-
applied: false,
152+
reason: format!("Decompose plan failed: {}", error),
124153
});
125154
}
126155
}
127-
Err(error) => {
128-
decompose_seen.insert(finding.file.clone());
129-
skipped.push(SkippedFile {
130-
file: finding.file.clone(),
131-
reason: format!("Decompose plan failed: {}", error),
132-
});
133-
}
134156
}
135157
}
136158

137-
doc_fixes::apply_stale_doc_reference_fixes(result, &mut fixes);
138-
doc_fixes::apply_broken_doc_reference_fixes(result, root, &mut fixes);
139-
parameter_fixes::generate_parameter_fixes(result, root, &mut fixes, &mut skipped);
140-
test_gen_fixes::generate_test_file_fixes(
141-
result,
142-
root,
143-
&mut new_files,
144-
&mut fixes,
145-
&mut skipped,
146-
);
147-
test_gen_fixes::generate_test_method_fixes(result, root, &mut fixes, &mut skipped);
148-
compiler_warning_fixes::generate_compiler_warning_fixes(result, root, &mut fixes, &mut skipped);
149-
comment_fixes::generate_comment_fixes(result, root, &mut fixes, &mut skipped);
150-
near_duplicate_fixes::generate_near_duplicate_fixes(result, root, &mut fixes, &mut skipped);
151-
intra_duplicate_fixes::generate_intra_duplicate_fixes(result, root, &mut fixes, &mut skipped);
159+
if finding_enabled(&AuditFinding::StaleDocReference) {
160+
doc_fixes::apply_stale_doc_reference_fixes(result, &mut fixes);
161+
}
162+
if finding_enabled(&AuditFinding::BrokenDocReference) {
163+
doc_fixes::apply_broken_doc_reference_fixes(result, root, &mut fixes);
164+
}
165+
if finding_enabled(&AuditFinding::UnusedParameter) {
166+
parameter_fixes::generate_parameter_fixes(result, root, &mut fixes, &mut skipped);
167+
}
168+
if finding_enabled(&AuditFinding::MissingTestFile) {
169+
test_gen_fixes::generate_test_file_fixes(
170+
result,
171+
root,
172+
&mut new_files,
173+
&mut fixes,
174+
&mut skipped,
175+
);
176+
}
177+
if finding_enabled(&AuditFinding::MissingTestMethod) {
178+
test_gen_fixes::generate_test_method_fixes(result, root, &mut fixes, &mut skipped);
179+
}
180+
if finding_enabled(&AuditFinding::CompilerWarning) {
181+
compiler_warning_fixes::generate_compiler_warning_fixes(result, root, &mut fixes, &mut skipped);
182+
}
183+
if finding_enabled(&AuditFinding::TodoMarker)
184+
|| finding_enabled(&AuditFinding::LegacyComment)
185+
{
186+
comment_fixes::generate_comment_fixes(result, root, &mut fixes, &mut skipped);
187+
}
188+
if finding_enabled(&AuditFinding::NearDuplicate) {
189+
near_duplicate_fixes::generate_near_duplicate_fixes(result, root, &mut fixes, &mut skipped);
190+
}
191+
if finding_enabled(&AuditFinding::IntraMethodDuplicate) {
192+
intra_duplicate_fixes::generate_intra_duplicate_fixes(result, root, &mut fixes, &mut skipped);
193+
}
152194

153195
let mut fixes = merge_fixes_per_file(fixes);
154196

src/core/refactor/plan/planner.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,11 +589,11 @@ fn plan_audit_stage(
589589
crate::code_audit::audit_path_with_id(component_id, &root.to_string_lossy())?
590590
};
591591

592-
let mut fix_result = super::generate::generate_audit_fixes(&result, root);
593592
let policy = fixer::FixPolicy {
594593
only: (!only.is_empty()).then_some(only.to_vec()),
595594
exclude: exclude.to_vec(),
596595
};
596+
let mut fix_result = super::generate::generate_audit_fixes(&result, root, &policy);
597597
let preflight_context = fixer::PreflightContext { root };
598598
let (fix_result, policy_summary, changed_files, stage_warnings): (
599599
fixer::FixResult,

src/core/refactor/plan/verify.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,12 @@ pub fn run_audit_refactor(
121121

122122
iterations.push(iteration_summary);
123123
} else {
124-
let root = Path::new(&current_result.source_path);
125-
let mut fix_result = super::generate::generate_audit_fixes(&current_result, root);
126124
let policy = fixer::FixPolicy {
127125
only: (!only_kinds.is_empty()).then_some(only_kinds.to_vec()),
128126
exclude: exclude_kinds.to_vec(),
129127
};
128+
let root = Path::new(&current_result.source_path);
129+
let mut fix_result = super::generate::generate_audit_fixes(&current_result, root, &policy);
130130
let preflight_context = fixer::PreflightContext { root };
131131
final_policy_summary =
132132
fixer::apply_fix_policy(&mut fix_result, false, &policy, &preflight_context);
@@ -151,12 +151,12 @@ fn run_fix_iteration(
151151
fixer::PolicySummary,
152152
AuditRefactorIterationSummary,
153153
)> {
154-
let root = Path::new(&audit_result.source_path);
155-
let mut fix_result = super::generate::generate_audit_fixes(audit_result, root);
156154
let policy = fixer::FixPolicy {
157155
only: (!only_kinds.is_empty()).then_some(only_kinds.to_vec()),
158156
exclude: exclude_kinds.to_vec(),
159157
};
158+
let root = Path::new(&audit_result.source_path);
159+
let mut fix_result = super::generate::generate_audit_fixes(audit_result, root, &policy);
160160
let preflight_context = fixer::PreflightContext { root };
161161
let policy_summary =
162162
fixer::apply_fix_policy(&mut fix_result, true, &policy, &preflight_context);

0 commit comments

Comments
 (0)