Skip to content

Commit 95edc06

Browse files
committed
fix(rustfix): dont apply same suggestion twice
This assumes that if any of the machine applicable fixes in a diagnostic suggestion is a duplicate, we should see the entire suggestion as a duplicate.
1 parent 5b05a3b commit 95edc06

File tree

4 files changed

+32
-10
lines changed

4 files changed

+32
-10
lines changed

crates/rustfix/src/lib.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,19 @@ impl CodeFix {
253253

254254
/// Applies multiple `suggestions` to the given `code`.
255255
pub fn apply_suggestions(code: &str, suggestions: &[Suggestion]) -> Result<String, Error> {
256+
let mut already_applied = HashSet::new();
256257
let mut fix = CodeFix::new(code);
257258
for suggestion in suggestions.iter().rev() {
259+
// This assumes that if any of the machine applicable fixes in
260+
// a diagnostic suggestion is a duplicate, we should see the
261+
// entire suggestion as a duplicate.
262+
if suggestion
263+
.solutions
264+
.iter()
265+
.any(|sol| !already_applied.insert(sol))
266+
{
267+
continue;
268+
}
258269
fix.apply(suggestion)?;
259270
}
260271
fix.finish()

crates/rustfix/tests/everything/dedup-suggestions.fixed.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
macro_rules! foo {
77
($x:ident) => {
8-
pub unsafe fn $x() { unsafe { unsafe {
8+
pub unsafe fn $x() { unsafe {
99
let _ = String::new().as_mut_vec();
10-
}}}
10+
}}
1111
};
1212
}
1313

src/cargo/ops/fix.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -735,12 +735,23 @@ fn rustfix_and_fix(
735735
});
736736
let mut fixed = CodeFix::new(&code);
737737

738-
// As mentioned above in `rustfix_crate`, we don't immediately warn
739-
// about suggestions that fail to apply here, and instead we save them
740-
// off for later processing.
738+
let mut already_applied = HashSet::new();
741739
for suggestion in suggestions.iter().rev() {
740+
// This assumes that if any of the machine applicable fixes in
741+
// a diagnostic suggestion is a duplicate, we should see the
742+
// entire suggestion as a duplicate.
743+
if suggestion
744+
.solutions
745+
.iter()
746+
.any(|sol| !already_applied.insert(sol))
747+
{
748+
continue;
749+
}
742750
match fixed.apply(suggestion) {
743751
Ok(()) => fixed_file.fixes_applied += 1,
752+
// As mentioned above in `rustfix_crate`, we don't immediately
753+
// warn about suggestions that fail to apply here, and instead
754+
// we save them off for later processing.
744755
Err(e) => fixed_file.errors_applying_fixes.push(e.to_string()),
745756
}
746757
}

tests/testsuite/fix.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,21 +1924,21 @@ fn fix_only_once_for_duplicates() {
19241924
.build();
19251925

19261926
p.cargo("fix --allow-no-vcs")
1927-
.with_stderr_contains(
1927+
.with_stderr(
19281928
"\
19291929
[CHECKING] foo v0.0.1 ([CWD])
1930-
[FIXED] src/lib.rs (2 fixes)
1930+
[FIXED] src/lib.rs (1 fix)
1931+
[FINISHED] `dev` profile [..]
19311932
",
19321933
)
1933-
.with_stderr_contains("[WARNING] unnecessary `unsafe` block[..]")
19341934
.run();
19351935

19361936
assert_eq!(
19371937
p.read_file("src/lib.rs").matches("unsafe").count(),
1938-
5,
1938+
4,
19391939
"unsafe keyword in src/lib.rs:\n\
19401940
2 in lint name;\n\
19411941
1 from original unsafe fn;\n\
1942-
2 from newly-applied unsafe blocks"
1942+
1 from newly-applied unsafe blocks"
19431943
);
19441944
}

0 commit comments

Comments
 (0)