Skip to content

Commit 17f56c5

Browse files
committed
Auto merge of #44215 - oli-obk:import_sugg, r=nrc
don't suggest placing `use` statements into expanded code r? @nrc fixes #44210 ```rust #[derive(Debug)] struct Foo; type X = Path; ``` will try to place `use std::path::Path;` between `#[derive(Debug)]` and `struct Foo;` I am not sure how to obtain a span before the first attribute, because derive attributes are removed during expansion. It would be trivial to detect this case and place the `use` after the item, but that would be somewhat weird I think.
2 parents 1b55d19 + f0e7a5b commit 17f56c5

File tree

5 files changed

+70
-30
lines changed

5 files changed

+70
-30
lines changed

src/librustc_resolve/lib.rs

+37-17
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
605605
ItemKind::Use(..) => {
606606
// don't suggest placing a use before the prelude
607607
// import or other generated ones
608-
if item.span == DUMMY_SP {
608+
if item.span.ctxt().outer().expn_info().is_none() {
609609
self.span = Some(item.span.with_hi(item.span.lo()));
610610
self.found_use = true;
611611
return;
@@ -615,11 +615,22 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
615615
ItemKind::ExternCrate(_) => {}
616616
// but place them before the first other item
617617
_ => if self.span.map_or(true, |span| item.span < span ) {
618-
self.span = Some(item.span.with_hi(item.span.lo()));
618+
if item.span.ctxt().outer().expn_info().is_none() {
619+
// don't insert between attributes and an item
620+
if item.attrs.is_empty() {
621+
self.span = Some(item.span.with_hi(item.span.lo()));
622+
} else {
623+
// find the first attribute on the item
624+
for attr in &item.attrs {
625+
if self.span.map_or(true, |span| attr.span < span) {
626+
self.span = Some(attr.span.with_hi(attr.span.lo()));
627+
}
628+
}
629+
}
630+
}
619631
},
620632
}
621633
}
622-
assert!(self.span.is_some(), "a file can't have no items and emit suggestions");
623634
}
624635
}
625636

@@ -3553,8 +3564,7 @@ impl<'a> Resolver<'a> {
35533564
};
35543565
visit::walk_crate(&mut finder, krate);
35553566
if !candidates.is_empty() {
3556-
let span = finder.span.expect("did not find module");
3557-
show_candidates(&mut err, span, &candidates, better, finder.found_use);
3567+
show_candidates(&mut err, finder.span, &candidates, better, finder.found_use);
35583568
}
35593569
err.emit();
35603570
}
@@ -3748,7 +3758,8 @@ fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, St
37483758
/// entities with that name in all crates. This method allows outputting the
37493759
/// results of this search in a programmer-friendly way
37503760
fn show_candidates(err: &mut DiagnosticBuilder,
3751-
span: Span,
3761+
// This is `None` if all placement locations are inside expansions
3762+
span: Option<Span>,
37523763
candidates: &[ImportSuggestion],
37533764
better: bool,
37543765
found_use: bool) {
@@ -3766,18 +3777,27 @@ fn show_candidates(err: &mut DiagnosticBuilder,
37663777
};
37673778
let msg = format!("possible {}candidate{} into scope", better, msg_diff);
37683779

3769-
for candidate in &mut path_strings {
3770-
// produce an additional newline to separate the new use statement
3771-
// from the directly following item.
3772-
let additional_newline = if found_use {
3773-
""
3774-
} else {
3775-
"\n"
3776-
};
3777-
*candidate = format!("use {};\n{}", candidate, additional_newline);
3778-
}
3780+
if let Some(span) = span {
3781+
for candidate in &mut path_strings {
3782+
// produce an additional newline to separate the new use statement
3783+
// from the directly following item.
3784+
let additional_newline = if found_use {
3785+
""
3786+
} else {
3787+
"\n"
3788+
};
3789+
*candidate = format!("use {};\n{}", candidate, additional_newline);
3790+
}
37793791

3780-
err.span_suggestions(span, &msg, path_strings);
3792+
err.span_suggestions(span, &msg, path_strings);
3793+
} else {
3794+
let mut msg = msg;
3795+
msg.push(':');
3796+
for candidate in path_strings {
3797+
msg.push('\n');
3798+
msg.push_str(&candidate);
3799+
}
3800+
}
37813801
}
37823802

37833803
/// A somewhat inefficient routine to obtain the name of a module.

src/test/ui/resolve/privacy-struct-ctor.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ error[E0423]: expected value, found struct `Z`
1010
|
1111
help: possible better candidate is found in another module, you can import it into scope
1212
|
13-
16 | use m::n::Z;
13+
22 | use m::n::Z;
1414
|
1515

1616
error[E0423]: expected value, found struct `S`
@@ -24,7 +24,7 @@ error[E0423]: expected value, found struct `S`
2424
|
2525
help: possible better candidate is found in another module, you can import it into scope
2626
|
27-
15 | use m::S;
27+
32 | use m::S;
2828
|
2929

3030
error[E0423]: expected value, found struct `xcrate::S`
@@ -38,7 +38,7 @@ error[E0423]: expected value, found struct `xcrate::S`
3838
|
3939
help: possible better candidate is found in another module, you can import it into scope
4040
|
41-
15 | use m::S;
41+
32 | use m::S;
4242
|
4343

4444
error[E0603]: tuple struct `Z` is private

src/test/ui/resolve/use_suggestion_placement.rs

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ mod m {
1616
pub const A: i32 = 0;
1717
}
1818

19+
mod foo {
20+
#[derive(Debug)]
21+
pub struct Foo;
22+
23+
// test whether the use suggestion isn't
24+
// placed into the expansion of `#[derive(Debug)]
25+
type Bar = Path;
26+
}
27+
1928
fn main() {
2029
y!();
2130
let _ = A;
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
1+
error[E0412]: cannot find type `Path` in this scope
2+
--> $DIR/use_suggestion_placement.rs:25:16
3+
|
4+
25 | type Bar = Path;
5+
| ^^^^ not found in this scope
6+
|
7+
help: possible candidate is found in another module, you can import it into scope
8+
|
9+
21 | use std::path::Path;
10+
|
11+
112
error[E0425]: cannot find value `A` in this scope
2-
--> $DIR/use_suggestion_placement.rs:21:13
13+
--> $DIR/use_suggestion_placement.rs:30:13
314
|
4-
21 | let _ = A;
15+
30 | let _ = A;
516
| ^ not found in this scope
617
|
718
help: possible candidate is found in another module, you can import it into scope
@@ -10,9 +21,9 @@ help: possible candidate is found in another module, you can import it into scop
1021
|
1122

1223
error[E0412]: cannot find type `HashMap` in this scope
13-
--> $DIR/use_suggestion_placement.rs:26:23
24+
--> $DIR/use_suggestion_placement.rs:35:23
1425
|
15-
26 | type Dict<K, V> = HashMap<K, V>;
26+
35 | type Dict<K, V> = HashMap<K, V>;
1627
| ^^^^^^^ not found in this scope
1728
|
1829
help: possible candidates are found in other modules, you can import them into scope
@@ -23,16 +34,16 @@ help: possible candidates are found in other modules, you can import them into s
2334
|
2435

2536
error[E0091]: type parameter `K` is unused
26-
--> $DIR/use_suggestion_placement.rs:26:15
37+
--> $DIR/use_suggestion_placement.rs:35:15
2738
|
28-
26 | type Dict<K, V> = HashMap<K, V>;
39+
35 | type Dict<K, V> = HashMap<K, V>;
2940
| ^ unused type parameter
3041

3142
error[E0091]: type parameter `V` is unused
32-
--> $DIR/use_suggestion_placement.rs:26:18
43+
--> $DIR/use_suggestion_placement.rs:35:18
3344
|
34-
26 | type Dict<K, V> = HashMap<K, V>;
45+
35 | type Dict<K, V> = HashMap<K, V>;
3546
| ^ unused type parameter
3647

37-
error: aborting due to 4 previous errors
48+
error: aborting due to 5 previous errors
3849

src/test/ui/span/issue-35987.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ error[E0404]: expected trait, found type parameter `Add`
66
|
77
help: possible better candidate is found in another module, you can import it into scope
88
|
9-
11 | use std::ops::Add;
9+
13 | use std::ops::Add;
1010
|
1111

1212
error[E0601]: main function not found

0 commit comments

Comments
 (0)