rust-lang / cargo

The Rust package manager
https://doc.rust-lang.org/cargo
Apache License 2.0
12.58k stars 2.38k forks source link

cannot fix with overlapping suggestions #13026

Open ehuss opened 3 years ago

ehuss commented 3 years ago

Some suggestions include overlapping regions. These cause rustfix to fail with an error like:

Could not replace range 22...47 in file -- maybe parts of it were already replaced?

An example that triggers this is the following where multiple trait bounds are to be removed:

pub type MyResult<T, E: std::error::Error + Send + Sync> = Result<T, E>;

This results in the following suggestion:

warning: bounds on generic parameters are not enforced in type aliases
 --> src/main.rs:1:25
  |
1 | pub type MyResult<T, E: std::error::Error + Send + Sync> = Result<T, E>;
  |                         ^^^^^^^^^^^^^^^^^   ^^^^   ^^^^
  |
  = note: `#[warn(type_alias_bounds)]` on by default
help: the bound will not be checked when the type alias is used, and should be removed
  |
1 - pub type MyResult<T, E: std::error::Error + Send + Sync> = Result<T, E>;
1 + pub type MyResult<T, E> = Result<T, E>;
  |

With the suggested JSON:

{
    "reason": "compiler-message",
    "package_id": "z2 0.1.0 (path+file:///foo)",
    "manifest_path": "/foo/Cargo.toml",
    "target":
    {
        "kind":
        [
            "bin"
        ],
        "crate_types":
        [
            "bin"
        ],
        "name": "z2",
        "src_path": "/foo/src/main.rs",
        "edition": "2018",
        "doc": true,
        "doctest": false,
        "test": true
    },
    "message":
    {
        "rendered": "warning: bounds on generic parameters are not enforced in type aliases\n --> src/main.rs:1:25\n  |\n1 | pub type MyResult<T, E: std::error::Error + Send + Sync> = Result<T, E>;\n  |                         ^^^^^^^^^^^^^^^^^   ^^^^   ^^^^\n  |\n  = note: `#[warn(type_alias_bounds)]` on by default\nhelp: the bound will not be checked when the type alias is used, and should be removed\n  |\n1 - pub type MyResult<T, E: std::error::Error + Send + Sync> = Result<T, E>;\n1 + pub type MyResult<T, E> = Result<T, E>;\n  | \n\n",
        "children":
        [
            {
                "children":
                [],
                "code": null,
                "level": "note",
                "message": "`#[warn(type_alias_bounds)]` on by default",
                "rendered": null,
                "spans":
                []
            },
            {
                "children":
                [],
                "code": null,
                "level": "help",
                "message": "the bound will not be checked when the type alias is used, and should be removed",
                "rendered": null,
                "spans":
                [
                    {
                        "byte_end": 41,
                        "byte_start": 22,
                        "column_end": 42,
                        "column_start": 23,
                        "expansion": null,
                        "file_name": "src/main.rs",
                        "is_primary": true,
                        "label": null,
                        "line_end": 1,
                        "line_start": 1,
                        "suggested_replacement": "",
                        "suggestion_applicability": "MachineApplicable",
                        "text":
                        [
                            {
                                "highlight_end": 42,
                                "highlight_start": 23,
                                "text": "pub type MyResult<T, E: std::error::Error + Send + Sync> = Result<T, E>;"
                            }
                        ]
                    },
                    {
                        "byte_end": 48,
                        "byte_start": 22,
                        "column_end": 49,
                        "column_start": 23,
                        "expansion": null,
                        "file_name": "src/main.rs",
                        "is_primary": true,
                        "label": null,
                        "line_end": 1,
                        "line_start": 1,
                        "suggested_replacement": "",
                        "suggestion_applicability": "MachineApplicable",
                        "text":
                        [
                            {
                                "highlight_end": 49,
                                "highlight_start": 23,
                                "text": "pub type MyResult<T, E: std::error::Error + Send + Sync> = Result<T, E>;"
                            }
                        ]
                    },
                    {
                        "byte_end": 55,
                        "byte_start": 22,
                        "column_end": 56,
                        "column_start": 23,
                        "expansion": null,
                        "file_name": "src/main.rs",
                        "is_primary": true,
                        "label": null,
                        "line_end": 1,
                        "line_start": 1,
                        "suggested_replacement": "",
                        "suggestion_applicability": "MachineApplicable",
                        "text":
                        [
                            {
                                "highlight_end": 56,
                                "highlight_start": 23,
                                "text": "pub type MyResult<T, E: std::error::Error + Send + Sync> = Result<T, E>;"
                            }
                        ]
                    }
                ]
            }
        ],
        "code":
        {
            "code": "type_alias_bounds",
            "explanation": null
        },
        "level": "warning",
        "message": "bounds on generic parameters are not enforced in type aliases",
        "spans":
        [
            {
                "byte_end": 41,
                "byte_start": 24,
                "column_end": 42,
                "column_start": 25,
                "expansion": null,
                "file_name": "src/main.rs",
                "is_primary": true,
                "label": null,
                "line_end": 1,
                "line_start": 1,
                "suggested_replacement": null,
                "suggestion_applicability": null,
                "text":
                [
                    {
                        "highlight_end": 42,
                        "highlight_start": 25,
                        "text": "pub type MyResult<T, E: std::error::Error + Send + Sync> = Result<T, E>;"
                    }
                ]
            },
            {
                "byte_end": 48,
                "byte_start": 44,
                "column_end": 49,
                "column_start": 45,
                "expansion": null,
                "file_name": "src/main.rs",
                "is_primary": true,
                "label": null,
                "line_end": 1,
                "line_start": 1,
                "suggested_replacement": null,
                "suggestion_applicability": null,
                "text":
                [
                    {
                        "highlight_end": 49,
                        "highlight_start": 45,
                        "text": "pub type MyResult<T, E: std::error::Error + Send + Sync> = Result<T, E>;"
                    }
                ]
            },
            {
                "byte_end": 55,
                "byte_start": 51,
                "column_end": 56,
                "column_start": 52,
                "expansion": null,
                "file_name": "src/main.rs",
                "is_primary": true,
                "label": null,
                "line_end": 1,
                "line_start": 1,
                "suggested_replacement": null,
                "suggestion_applicability": null,
                "text":
                [
                    {
                        "highlight_end": 56,
                        "highlight_start": 52,
                        "text": "pub type MyResult<T, E: std::error::Error + Send + Sync> = Result<T, E>;"
                    }
                ]
            }
        ]
    }
}

This has three overlapping spans that suggest a replacement of an empty string:

I think it might be feasible to support this. At least, the new diff output from rustc is able to handle it, and clicking the "fix" suggestions in my editor is able to handle it (the regions are "smart" and know when the text within it is modified).

Note: This is relatively new behavior introduced by rust-lang/rustfix#195.

LuuuXXX commented 6 months ago

Attempt to resolve. @rustbot claim

torhovland commented 2 months ago

The particular example mentioned in the issue is (now) being successfully handled by cargo fix. I think this issue needs an updated test case.

torhovland commented 3 weeks ago

@rustbot label: +S-needs-info, -S-accepted