From 5158063c3ec1e1dc8d9b0a0806e29d6c6e54d765 Mon Sep 17 00:00:00 2001 From: David Wood Date: Fri, 12 Apr 2019 01:53:32 +0200 Subject: [PATCH] Switch to multipart suggestions. This commit changes the suggestion so that it is split into multiple parts in an effort to reduce the impact the applied suggestion could have on formatting. --- src/librustc_resolve/error_reporting.rs | 57 +++++----- src/librustc_resolve/lib.rs | 11 +- src/librustc_resolve/resolve_imports.rs | 12 +-- src/test/ui/issue-59764.fixed | 134 ------------------------ src/test/ui/issue-59764.rs | 1 - src/test/ui/issue-59764.stderr | 61 +++++------ 6 files changed, 68 insertions(+), 208 deletions(-) delete mode 100644 src/test/ui/issue-59764.fixed diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs index 5372c4ee44bdc..931bce91d7d43 100644 --- a/src/librustc_resolve/error_reporting.rs +++ b/src/librustc_resolve/error_reporting.rs @@ -617,14 +617,12 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { _ => format!("{}", ident), }; - // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove - // intermediate segments. - let (mut span, mut correction) = (directive.span, - format!("{}::{}", module_name, import)); - - if directive.is_nested() { - span = directive.use_span; - + let mut corrections: Vec<(Span, String)> = Vec::new(); + if !directive.is_nested() { + // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove + // intermediate segments. + corrections.push((directive.span, format!("{}::{}", module_name, import))); + } else { // Find the binding span (and any trailing commas and spaces). // ie. `use a::b::{c, d, e};` // ^^^ @@ -652,6 +650,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } debug!("check_for_module_export_macro: removal_span={:?}", removal_span); + // Remove the `removal_span`. + corrections.push((removal_span, "".to_string())); + // Find the span after the crate name and if it has nested imports immediatately // after the crate name already. // ie. `use a::b::{c, d};` @@ -666,34 +667,32 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let source_map = self.resolver.session.source_map(); - // Remove two bytes at the end to keep all but the `};` characters. - // ie. `{b::{c, d}, e::{f, g}};` - // ^^^^^^^^^^^^^^^^^^^^^ - let end_bytes = BytePos(if has_nested { 2 } else { 1 }); - let mut remaining_span = after_crate_name.with_hi( - after_crate_name.hi() - end_bytes); - if has_nested { - // Remove two bytes at the start to keep all but the initial `{` character. - // ie. `{b::{c, d}, e::{f, g}` - // ^^^^^^^^^^^^^^^^^^^^ - remaining_span = remaining_span.with_lo(after_crate_name.lo() + BytePos(1)); + // Add the import to the start, with a `{` if required. + let start_point = source_map.start_point(after_crate_name); + if let Ok(start_snippet) = source_map.span_to_snippet(start_point) { + corrections.push(( + start_point, + if has_nested { + // In this case, `start_snippet` must equal '{'. + format!("{}{}, ", start_snippet, import) + } else { + // In this case, add a `{`, then the moved import, then whatever + // was there before. + format!("{{{}, {}", import, start_snippet) + } + )); } - // Calculate the number of characters into a snippet to remove the removal - // span. - let lo = removal_span.lo() - remaining_span.lo(); - let hi = lo + (removal_span.hi() - removal_span.lo()); - if let Ok(mut remaining) = source_map.span_to_snippet(remaining_span) { - // Remove the original location of the binding. - remaining.replace_range((lo.0 as usize)..(hi.0 as usize), ""); - correction = format!("use {}::{{{}, {}}};", module_name, import, remaining); + // Add a `};` to the end if nested, matching the `{` added at the start. + if !has_nested { + corrections.push((source_map.end_point(after_crate_name), + "};".to_string())); } } let suggestion = Some(( - span, + corrections, String::from("a macro with this name exists at the root of the crate"), - correction, Applicability::MaybeIncorrect, )); let note = vec![ diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b33356c2ba7ae..c1353d771c26f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -139,8 +139,8 @@ impl Ord for BindingError { } } -/// A span, message, replacement text, and applicability. -type Suggestion = (Span, String, String, Applicability); +/// A vector of spans and replacements, a message and applicability. +type Suggestion = (Vec<(Span, String)>, String, Applicability); enum ResolutionError<'a> { /// Error E0401: can't use type or const parameters from outer function. @@ -390,8 +390,8 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>, "failed to resolve: {}", &label); err.span_label(span, label); - if let Some((span, msg, suggestion, applicability)) = suggestion { - err.span_suggestion(span, &msg, suggestion, applicability); + if let Some((suggestions, msg, applicability)) = suggestion { + err.multipart_suggestion(&msg, suggestions, applicability); } err @@ -3774,9 +3774,8 @@ impl<'a> Resolver<'a> { ( String::from("unresolved import"), Some(( - ident.span, + vec![(ident.span, candidate.path.to_string())], String::from("a similar path exists"), - candidate.path.to_string(), Applicability::MaybeIncorrect, )), ) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index ef5f0f54ee369..62af6e19603c4 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -793,8 +793,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { diag.span_label(err.span, label); } - if let Some((span, msg, suggestion, applicability)) = err.suggestion { - diag.span_suggestion(span, &msg, suggestion, applicability); + if let Some((suggestions, msg, applicability)) = err.suggestion { + diag.multipart_suggestion(&msg, suggestions, applicability); } } @@ -947,9 +947,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { label: None, note, suggestion: Some(( - span, + vec![(span, Segment::names_to_string(&suggestion))], String::from("a similar path exists"), - Segment::names_to_string(&suggestion), Applicability::MaybeIncorrect, )), } @@ -1113,8 +1112,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let lev_suggestion = find_best_match_for_name(names, &ident.as_str(), None) .map(|suggestion| - (ident.span, String::from("a similar name exists in the module"), - suggestion.to_string(), Applicability::MaybeIncorrect) + (vec![(ident.span, suggestion.to_string())], + String::from("a similar name exists in the module"), + Applicability::MaybeIncorrect) ); let (suggestion, note) = match self.check_for_module_export_macro( diff --git a/src/test/ui/issue-59764.fixed b/src/test/ui/issue-59764.fixed deleted file mode 100644 index ad3bab50cfca3..0000000000000 --- a/src/test/ui/issue-59764.fixed +++ /dev/null @@ -1,134 +0,0 @@ -// aux-build:issue-59764.rs -// compile-flags:--extern issue_59764 -// edition:2018 -// run-rustfix - -#![allow(warnings)] - -// This tests the suggestion to import macros from the root of a crate. This aims to capture -// the case where a user attempts to import a macro from the definition location instead of the -// root of the crate and the macro is annotated with `#![macro_export]`. - -// Edge cases.. - -mod multiple_imports_same_line_at_end { - use issue_59764::{makro, foo::{baz}}; - //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] -} - -mod multiple_imports_multiline_at_end_trailing_comma { - use issue_59764::{makro, foo::{ - baz, - //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] - }}; -} - -mod multiple_imports_multiline_at_end { - use issue_59764::{makro, foo::{ - baz, - //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] - }}; -} - -mod multiple_imports_same_line_in_middle { - use issue_59764::{makro, foo::{baz, foobar}}; - //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] -} - -mod multiple_imports_multiline_in_middle_trailing_comma { - use issue_59764::{makro, foo::{ - baz, - //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] - foobar, - }}; -} - -mod multiple_imports_multiline_in_middle { - use issue_59764::{makro, foo::{ - baz, - //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] - foobar - }}; -} - -mod nested_imports { - use issue_59764::{makro, foobaz}; - //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] -} - -mod nested_multiple_imports { - use issue_59764::{makro, foobaz, foo::{baz}}; - //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] -} - -mod nested_multiline_multiple_imports_trailing_comma { - use issue_59764::{makro, - foobaz, - foo::{ - baz, - //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] - }, - }; -} - -mod nested_multiline_multiple_imports { - use issue_59764::{makro, - foobaz, - foo::{ - baz, - //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] - } - }; -} - -mod doubly_nested_multiple_imports { - use issue_59764::{makro, foobaz, foo::{baz, barbaz::{barfoo}}}; - //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] -} - -mod doubly_multiline_nested_multiple_imports { - use issue_59764::{makro, - foobaz, - foo::{ - baz, - //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] - barbaz::{ - barfoo, - } - } - }; -} - -mod renamed_import { - use issue_59764::makro as baz; - //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] -} - -mod renamed_multiple_imports { - use issue_59764::{makro as foobar, foo::{baz}}; - //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] -} - -mod lots_of_whitespace { - use issue_59764::{makro as foobar, - - foobaz, - - - foo::{baz} //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] - - }; -} - -// Simple case.. - -use issue_59764::makro; -//~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] - -makro!(bar); -//~^ ERROR cannot determine resolution for the macro `makro` - -fn main() { - bar(); - //~^ ERROR cannot find function `bar` in this scope [E0425] -} diff --git a/src/test/ui/issue-59764.rs b/src/test/ui/issue-59764.rs index 0c6787691de0a..09dee8c273268 100644 --- a/src/test/ui/issue-59764.rs +++ b/src/test/ui/issue-59764.rs @@ -1,7 +1,6 @@ // aux-build:issue-59764.rs // compile-flags:--extern issue_59764 // edition:2018 -// run-rustfix #![allow(warnings)] diff --git a/src/test/ui/issue-59764.stderr b/src/test/ui/issue-59764.stderr index 89b1f84605dc7..924e69f5f9703 100644 --- a/src/test/ui/issue-59764.stderr +++ b/src/test/ui/issue-59764.stderr @@ -1,5 +1,5 @@ error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:15:33 + --> $DIR/issue-59764.rs:14:33 | LL | use issue_59764::foo::{baz, makro}; | ^^^^^ no `makro` in `foo` @@ -8,10 +8,10 @@ LL | use issue_59764::foo::{baz, makro}; help: a macro with this name exists at the root of the crate | LL | use issue_59764::{makro, foo::{baz}}; - | + | ^^^^^^^^^ --^^ error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:22:9 + --> $DIR/issue-59764.rs:21:9 | LL | makro, | ^^^^^ no `makro` in `foo` @@ -26,7 +26,7 @@ LL | }}; | error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:29:9 + --> $DIR/issue-59764.rs:28:9 | LL | makro | ^^^^^ no `makro` in `foo` @@ -41,7 +41,7 @@ LL | }}; | error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:34:33 + --> $DIR/issue-59764.rs:33:33 | LL | use issue_59764::foo::{baz, makro, foobar}; | ^^^^^ no `makro` in `foo` @@ -50,10 +50,10 @@ LL | use issue_59764::foo::{baz, makro, foobar}; help: a macro with this name exists at the root of the crate | LL | use issue_59764::{makro, foo::{baz, foobar}}; - | + | ^^^^^^^^^ -- ^^ error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:41:9 + --> $DIR/issue-59764.rs:40:9 | LL | makro, | ^^^^^ no `makro` in `foo` @@ -69,7 +69,7 @@ LL | }}; | error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:49:9 + --> $DIR/issue-59764.rs:48:9 | LL | makro, | ^^^^^ no `makro` in `foo` @@ -85,7 +85,7 @@ LL | }}; | error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:55:31 + --> $DIR/issue-59764.rs:54:31 | LL | use issue_59764::{foobaz, foo::makro}; | ^^^^^^^^^^ no `makro` in `foo` @@ -94,10 +94,10 @@ LL | use issue_59764::{foobaz, foo::makro}; help: a macro with this name exists at the root of the crate | LL | use issue_59764::{makro, foobaz}; - | + | ^^^^^^^ -- error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:60:42 + --> $DIR/issue-59764.rs:59:42 | LL | use issue_59764::{foobaz, foo::{baz, makro}}; | ^^^^^ no `makro` in `foo` @@ -106,10 +106,10 @@ LL | use issue_59764::{foobaz, foo::{baz, makro}}; help: a macro with this name exists at the root of the crate | LL | use issue_59764::{makro, foobaz, foo::{baz}}; - | + | ^^^^^^^ -- error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:69:13 + --> $DIR/issue-59764.rs:68:13 | LL | makro, | ^^^^^ no `makro` in `foo` @@ -122,11 +122,10 @@ LL | foobaz, LL | foo::{ LL | baz, LL | -LL | }, - ... + | error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:79:13 + --> $DIR/issue-59764.rs:78:13 | LL | makro | ^^^^^ no `makro` in `foo` @@ -139,11 +138,10 @@ LL | foobaz, LL | foo::{ LL | baz, LL | -LL | } - ... + | error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:85:42 + --> $DIR/issue-59764.rs:84:42 | LL | use issue_59764::{foobaz, foo::{baz, makro, barbaz::{barfoo}}}; | ^^^^^ no `makro` in `foo` @@ -152,10 +150,10 @@ LL | use issue_59764::{foobaz, foo::{baz, makro, barbaz::{barfoo}}}; help: a macro with this name exists at the root of the crate | LL | use issue_59764::{makro, foobaz, foo::{baz, barbaz::{barfoo}}}; - | + | ^^^^^^^ -- error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:94:13 + --> $DIR/issue-59764.rs:93:13 | LL | makro, | ^^^^^ no `makro` in `foo` @@ -168,11 +166,10 @@ LL | foobaz, LL | foo::{ LL | baz, LL | -LL | barbaz::{ - ... + | error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:103:9 + --> $DIR/issue-59764.rs:102:9 | LL | use issue_59764::foo::makro as baz; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `makro` in `foo` @@ -184,7 +181,7 @@ LL | use issue_59764::makro as baz; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:108:33 + --> $DIR/issue-59764.rs:107:33 | LL | use issue_59764::foo::{baz, makro as foobar}; | ^^^^^^^^^^^^^^^ no `makro` in `foo` @@ -193,10 +190,10 @@ LL | use issue_59764::foo::{baz, makro as foobar}; help: a macro with this name exists at the root of the crate | LL | use issue_59764::{makro as foobar, foo::{baz}}; - | + | ^^^^^^^^^^^^^^^^^^^ --^^ error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:121:17 + --> $DIR/issue-59764.rs:120:17 | LL | makro as foobar} | ^^^^^^^^^^^^^^^ no `makro` in `foo` @@ -204,16 +201,16 @@ LL | makro as foobar} = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined help: a macro with this name exists at the root of the crate | -LL | use issue_59764::{makro as foobar, +LL | issue_59764::{makro as foobar, LL | LL | foobaz, LL | LL | LL | foo::{baz} - ... + | error[E0432]: unresolved import `issue_59764::foo::makro` - --> $DIR/issue-59764.rs:128:5 + --> $DIR/issue-59764.rs:127:5 | LL | use issue_59764::foo::makro; | ^^^^^^^^^^^^^^^^^^^^^^^ no `makro` in `foo` @@ -225,7 +222,7 @@ LL | use issue_59764::makro; | ^^^^^^^^^^^^^^^^^^ error: cannot determine resolution for the macro `makro` - --> $DIR/issue-59764.rs:131:1 + --> $DIR/issue-59764.rs:130:1 | LL | makro!(bar); | ^^^^^ @@ -233,7 +230,7 @@ LL | makro!(bar); = note: import resolution is stuck, try simplifying macro imports error[E0425]: cannot find function `bar` in this scope - --> $DIR/issue-59764.rs:135:5 + --> $DIR/issue-59764.rs:134:5 | LL | bar(); | ^^^ not found in this scope