Skip to content

Commit ba7d52a

Browse files
committed
Handle proc-macro spans pointing at attribute in suggestions
Hide invalid proc-macro suggestions and track spans coming from proc-macros pointing at attribute. Effectively, unless the proc-macro keeps user spans, suggestions will not be produced for the code they produce. Account for desugaring when checking if a span can be used for suggestions Fix rust-lang#106720.
1 parent ae3ab14 commit ba7d52a

File tree

68 files changed

+2898
-2659
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+2898
-2659
lines changed

compiler/rustc_ast_lowering/src/path.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -288,10 +288,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
288288
segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span)
289289
} else if generic_args.is_empty() {
290290
// If there are brackets, but not generic arguments, then use the opening bracket
291-
generic_args.span.with_hi(generic_args.span.lo() + BytePos(1))
291+
self.tcx.adjust_span(generic_args.span).with_hi(generic_args.span.lo() + BytePos(1))
292292
} else {
293293
// Else use an empty span right after the opening bracket.
294-
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo()
294+
self.tcx
295+
.adjust_span(generic_args.span)
296+
.with_lo(generic_args.span.lo() + BytePos(1))
297+
.shrink_to_lo()
295298
};
296299

297300
generic_args.args.insert_many(

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2250,12 +2250,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
22502250
Ok(string) => {
22512251
if string.starts_with("async ") {
22522252
let pos = args_span.lo() + BytePos(6);
2253-
(args_span.with_lo(pos).with_hi(pos), "move ")
2253+
(self.infcx.tcx.adjust_span(args_span).with_lo(pos).with_hi(pos), "move ")
22542254
} else if string.starts_with("async|") {
22552255
let pos = args_span.lo() + BytePos(5);
2256-
(args_span.with_lo(pos).with_hi(pos), " move")
2256+
(self.infcx.tcx.adjust_span(args_span).with_lo(pos).with_hi(pos), " move")
22572257
} else {
2258-
(args_span.shrink_to_lo(), "move ")
2258+
(self.infcx.tcx.adjust_span(args_span).shrink_to_lo(), "move ")
22592259
}
22602260
}
22612261
Err(_) => (args_span, "move |<args>| <body>"),

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -470,15 +470,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
470470
match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
471471
Ok(snippet) if snippet.starts_with('*') => {
472472
err.span_suggestion_verbose(
473-
span.with_hi(span.lo() + BytePos(1)),
473+
self.infcx.tcx.adjust_span(span).with_hi(span.lo() + BytePos(1)),
474474
"consider removing the dereference here",
475475
String::new(),
476476
Applicability::MaybeIncorrect,
477477
);
478478
}
479479
_ => {
480480
err.span_suggestion_verbose(
481-
span.shrink_to_lo(),
481+
self.infcx.tcx.adjust_span(span).shrink_to_lo(),
482482
"consider borrowing here",
483483
'&',
484484
Applicability::MaybeIncorrect,

compiler/rustc_builtin_macros/src/alloc_error_handler.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use thin_vec::{thin_vec, ThinVec};
1111

1212
pub fn expand(
1313
ecx: &mut ExtCtxt<'_>,
14-
_span: Span,
14+
span: Span,
1515
meta_item: &ast::MetaItem,
1616
item: Annotatable,
1717
) -> Vec<Annotatable> {
@@ -37,7 +37,7 @@ pub fn expand(
3737
};
3838

3939
// Generate a bunch of new items using the AllocFnFactory
40-
let span = ecx.with_def_site_ctxt(item.span);
40+
let span = ecx.with_def_site_ctxt(span);
4141

4242
// Generate item statements for the allocator methods.
4343
let stmts = thin_vec![generate_handler(ecx, item.ident, span, sig_span)];

compiler/rustc_const_eval/src/transform/check_consts/ops.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,15 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
256256
{
257257
let rhs_pos =
258258
span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
259-
let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
259+
let rhs_span =
260+
tcx.adjust_span(span).with_lo(rhs_pos).with_hi(rhs_pos);
260261
err.multipart_suggestion(
261262
"consider dereferencing here",
262263
vec![
263-
(span.shrink_to_lo(), deref.clone()),
264+
(
265+
tcx.adjust_span(span).shrink_to_lo(),
266+
deref.clone(),
267+
),
264268
(rhs_span, deref),
265269
],
266270
Applicability::MachineApplicable,

compiler/rustc_errors/src/diagnostic.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,10 @@ impl Diagnostic {
621621
.map(|(span, snippet)| SubstitutionPart { snippet, span })
622622
.collect::<Vec<_>>();
623623

624+
if !parts.iter().all(|sub| sub.span.can_be_used_for_suggestions()) {
625+
return self;
626+
}
627+
624628
parts.sort_unstable_by_key(|part| part.span);
625629

626630
assert!(!parts.is_empty());
@@ -711,6 +715,9 @@ impl Diagnostic {
711715
!(sp.is_empty() && suggestion.to_string().is_empty()),
712716
"Span must not be empty and have no suggestion"
713717
);
718+
if !sp.can_be_used_for_suggestions() {
719+
return self;
720+
}
714721
self.push_suggestion(CodeSuggestion {
715722
substitutions: vec![Substitution {
716723
parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
@@ -774,6 +781,9 @@ impl Diagnostic {
774781
!(sp.is_empty() && suggestions.iter().any(|suggestion| suggestion.is_empty())),
775782
"Span must not be empty and have no suggestion"
776783
);
784+
if !sp.can_be_used_for_suggestions() {
785+
return self;
786+
}
777787

778788
let substitutions = suggestions
779789
.into_iter()
@@ -799,12 +809,16 @@ impl Diagnostic {
799809
) -> &mut Self {
800810
let substitutions = suggestions
801811
.into_iter()
802-
.map(|sugg| {
812+
.filter_map(|sugg| {
803813
let mut parts = sugg
804814
.into_iter()
805815
.map(|(span, snippet)| SubstitutionPart { snippet, span })
806816
.collect::<Vec<_>>();
807817

818+
if !parts.iter().all(|sub| sub.span.can_be_used_for_suggestions()) {
819+
return None;
820+
}
821+
808822
parts.sort_unstable_by_key(|part| part.span);
809823

810824
assert!(!parts.is_empty());
@@ -819,7 +833,7 @@ impl Diagnostic {
819833
"suggestion must not have overlapping parts",
820834
);
821835

822-
Substitution { parts }
836+
Some(Substitution { parts })
823837
})
824838
.collect();
825839

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1355,7 +1355,7 @@ fn compare_number_of_method_arguments<'tcx>(
13551355
if pos == 0 {
13561356
arg.span
13571357
} else {
1358-
arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
1358+
tcx.adjust_span(arg.span).with_lo(trait_m_sig.decl.inputs[0].span.lo())
13591359
}
13601360
})
13611361
})
@@ -1371,7 +1371,7 @@ fn compare_number_of_method_arguments<'tcx>(
13711371
if pos == 0 {
13721372
arg.span
13731373
} else {
1374-
arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
1374+
tcx.adjust_span(arg.span).with_lo(impl_m_sig.decl.inputs[0].span.lo())
13751375
}
13761376
})
13771377
.unwrap_or_else(|| tcx.def_span(impl_m.def_id));
@@ -1468,7 +1468,8 @@ fn compare_synthetic_generics<'tcx>(
14681468

14691469
// in case there are no generics, take the spot between the function name
14701470
// and the opening paren of the argument list
1471-
let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi();
1471+
let new_generics_span =
1472+
tcx.adjust_span(tcx.def_ident_span(impl_def_id)?).shrink_to_hi();
14721473
// in case there are generics, just replace them
14731474
let generics_span =
14741475
impl_m.generics.span.substitute_dummy(new_generics_span);

compiler/rustc_hir_analysis/src/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ fn missing_items_err(
200200
let hi = full_impl_span.hi() - BytePos(1);
201201
// Point at the place right before the closing brace of the relevant `impl` to suggest
202202
// adding the associated item at the end of its body.
203-
let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi);
203+
let sugg_sp = tcx.adjust_span(full_impl_span).with_lo(hi).with_hi(hi);
204204
// Obtain the level of indentation ending in `sugg_sp`.
205205
let padding =
206206
tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new());

compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -610,10 +610,10 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
610610

611611
AngleBrackets::Available => {
612612
let (sugg_span, is_first) = if self.num_provided_lifetime_args() == 0 {
613-
(self.gen_args.span().unwrap().shrink_to_lo(), true)
613+
(self.tcx.adjust_span(self.gen_args.span().unwrap()).shrink_to_lo(), true)
614614
} else {
615615
let last_lt = &self.gen_args.args[self.num_provided_lifetime_args() - 1];
616-
(last_lt.span().shrink_to_hi(), false)
616+
(self.tcx.adjust_span(last_lt.span()).shrink_to_hi(), false)
617617
};
618618
let has_non_lt_args = self.num_provided_type_or_const_args() != 0;
619619
let has_bindings = !self.gen_args.bindings.is_empty();
@@ -658,14 +658,14 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
658658
);
659659
}
660660
AngleBrackets::Available => {
661-
let gen_args_span = self.gen_args.span().unwrap();
661+
let gen_args_span = self.tcx.adjust_span(self.gen_args.span().unwrap());
662662
let sugg_offset =
663663
self.get_lifetime_args_offset() + self.num_provided_type_or_const_args();
664664

665665
let (sugg_span, is_first) = if sugg_offset == 0 {
666-
(gen_args_span.shrink_to_lo(), true)
666+
(self.tcx.adjust_span(gen_args_span).shrink_to_lo(), true)
667667
} else {
668-
let arg_span = self.gen_args.args[sugg_offset - 1].span();
668+
let arg_span = self.tcx.adjust_span(self.gen_args.args[sugg_offset - 1].span());
669669
// If we came here then inferred lifetime's spans can only point
670670
// to either the opening bracket or to the space right after.
671671
// Both of these spans have an `hi` lower than or equal to the span
@@ -770,7 +770,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
770770
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
771771
let sugg = vec![
772772
(self.path_segment.ident.span, format!("{}::{}", snippet, self.path_segment.ident)),
773-
(span.with_lo(self.path_segment.ident.span.hi()), "".to_owned())
773+
(self.tcx.adjust_span(span).with_lo(self.path_segment.ident.span.hi()), "".to_owned())
774774
];
775775

776776
err.multipart_suggestion(
@@ -953,11 +953,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
953953
}
954954
} else if remove_entire_generics {
955955
let span = self
956-
.path_segment
957-
.args
958-
.unwrap()
959-
.span_ext()
960-
.unwrap()
956+
.tcx
957+
.adjust_span(self.path_segment.args.unwrap().span_ext().unwrap())
961958
.with_lo(self.path_segment.ident.span.hi());
962959

963960
let msg = format!(

compiler/rustc_hir_typeck/src/demand.rs

+41-20
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
647647
),
648648
),
649649
match &args[..] {
650-
[] => (base.span.shrink_to_hi().with_hi(deref.span.hi()), ")".to_string()),
650+
[] => (
651+
self.tcx.adjust_span(base.span).shrink_to_hi().with_hi(deref.span.hi()),
652+
")".to_string(),
653+
),
651654
[first, ..] => (base.span.between(first.span), ", ".to_string()),
652655
},
653656
]
@@ -771,8 +774,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
771774
"use `?` to coerce and return an appropriate `Err`, and wrap the resulting value \
772775
in `Ok` so the expression remains of type `Result`",
773776
vec![
774-
(expr.span.shrink_to_lo(), "Ok(".to_string()),
775-
(expr.span.shrink_to_hi(), "?)".to_string()),
777+
(self.tcx.adjust_span(expr.span).shrink_to_lo(), "Ok(".to_string()),
778+
(self.tcx.adjust_span(expr.span).shrink_to_hi(), "?)".to_string()),
776779
],
777780
Applicability::MaybeIncorrect,
778781
);
@@ -843,8 +846,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
843846
} else {
844847
return false;
845848
};
846-
if let Some(indent) =
847-
self.tcx.sess.source_map().indentation_before(span.shrink_to_lo())
849+
if let Some(indent) = self
850+
.tcx
851+
.sess
852+
.source_map()
853+
.indentation_before(self.tcx.adjust_span(span).shrink_to_lo())
848854
{
849855
// Add a semicolon, except after `}`.
850856
let semicolon =
@@ -853,7 +859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
853859
_ => ";",
854860
};
855861
err.span_suggestions(
856-
span.shrink_to_hi(),
862+
self.tcx.adjust_span(span).shrink_to_hi(),
857863
"try adding an expression at the end of the block",
858864
return_suggestions
859865
.into_iter()
@@ -931,8 +937,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
931937
}
932938

933939
vec![
934-
(expr.span.shrink_to_lo(), format!("{prefix}{variant}{open}")),
935-
(expr.span.shrink_to_hi(), close.to_owned()),
940+
(
941+
self.tcx.adjust_span(expr.span).shrink_to_lo(),
942+
format!("{prefix}{variant}{open}"),
943+
),
944+
(self.tcx.adjust_span(expr.span).shrink_to_hi(), close.to_owned()),
936945
]
937946
};
938947

@@ -1016,8 +1025,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10161025
err.multipart_suggestion(
10171026
format!("consider calling `{s}::new`"),
10181027
vec![
1019-
(expr.span.shrink_to_lo(), format!("{path}::new(")),
1020-
(expr.span.shrink_to_hi(), format!("){unwrap}")),
1028+
(self.tcx.adjust_span(expr.span).shrink_to_lo(), format!("{path}::new(")),
1029+
(self.tcx.adjust_span(expr.span).shrink_to_hi(), format!("){unwrap}")),
10211030
],
10221031
Applicability::MaybeIncorrect,
10231032
);
@@ -1271,7 +1280,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12711280
&& replace_prefix(&src, "\"", "b\"").is_some()
12721281
{
12731282
return Some((
1274-
sp.shrink_to_lo(),
1283+
self.tcx.adjust_span(sp).shrink_to_lo(),
12751284
"consider adding a leading `b`".to_string(),
12761285
"b".to_string(),
12771286
Applicability::MachineApplicable,
@@ -1468,7 +1477,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14681477
_ if sp == expr.span => {
14691478
if let Some(mut steps) = self.deref_steps(checked_ty, expected) {
14701479
let mut expr = expr.peel_blocks();
1471-
let mut prefix_span = expr.span.shrink_to_lo();
1480+
let mut prefix_span = self.tcx.adjust_span(expr.span).shrink_to_lo();
14721481
let mut remove = String::new();
14731482

14741483
// Try peeling off any existing `&` and `&mut` to reach our target type
@@ -1539,7 +1548,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15391548
return None;
15401549
} else if let Some(expr) = self.maybe_get_block_expr(expr) {
15411550
// prefix should be empty here..
1542-
(expr.span.shrink_to_lo(), "*".to_string())
1551+
(self.tcx.adjust_span(expr.span).shrink_to_lo(), "*".to_string())
15431552
} else {
15441553
(prefix_span, format!("{}{}", prefix, "*".repeat(steps)))
15451554
};
@@ -1596,7 +1605,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15961605
// `expr` is a literal field for a struct, only suggest if appropriate
15971606
if field.is_shorthand {
15981607
// This is a field literal
1599-
sugg.push((field.ident.span.shrink_to_lo(), format!("{}: ", field.ident)));
1608+
sugg.push((
1609+
self.tcx.adjust_span(field.ident.span).shrink_to_lo(),
1610+
format!("{}: ", field.ident),
1611+
));
16001612
} else {
16011613
// Likely a field was meant, but this field wasn't found. Do not suggest anything.
16021614
return false;
@@ -1652,16 +1664,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16521664
);
16531665

16541666
let close_paren = if expr.precedence().order() < PREC_POSTFIX {
1655-
sugg.push((expr.span.shrink_to_lo(), "(".to_string()));
1667+
sugg.push((self.tcx.adjust_span(expr.span).shrink_to_lo(), "(".to_string()));
16561668
")"
16571669
} else {
16581670
""
16591671
};
16601672

16611673
let mut cast_suggestion = sugg.clone();
1662-
cast_suggestion.push((expr.span.shrink_to_hi(), format!("{close_paren} as {expected_ty}")));
1674+
cast_suggestion.push((
1675+
self.tcx.adjust_span(expr.span).shrink_to_hi(),
1676+
format!("{close_paren} as {expected_ty}"),
1677+
));
16631678
let mut into_suggestion = sugg.clone();
1664-
into_suggestion.push((expr.span.shrink_to_hi(), format!("{close_paren}.into()")));
1679+
into_suggestion.push((
1680+
self.tcx.adjust_span(expr.span).shrink_to_hi(),
1681+
format!("{close_paren}.into()"),
1682+
));
16651683
let mut suffix_suggestion = sugg.clone();
16661684
suffix_suggestion.push((
16671685
if matches!(
@@ -1715,15 +1733,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17151733
"you can convert `{lhs_src}` from `{expected_ty}` to `{checked_ty}`, matching the type of `{src}`",
17161734
);
17171735
let suggestion = vec![
1718-
(lhs_expr.span.shrink_to_lo(), format!("{checked_ty}::from(")),
1719-
(lhs_expr.span.shrink_to_hi(), ")".to_string()),
1736+
(
1737+
self.tcx.adjust_span(lhs_expr.span).shrink_to_lo(),
1738+
format!("{checked_ty}::from("),
1739+
),
1740+
(self.tcx.adjust_span(lhs_expr.span).shrink_to_hi(), ")".to_string()),
17201741
];
17211742
(msg, suggestion)
17221743
} else {
17231744
let msg = format!("{msg} and panic if the converted value doesn't fit");
17241745
let mut suggestion = sugg.clone();
17251746
suggestion.push((
1726-
expr.span.shrink_to_hi(),
1747+
self.tcx.adjust_span(expr.span).shrink_to_hi(),
17271748
format!("{close_paren}.try_into().unwrap()"),
17281749
));
17291750
(msg, suggestion)

0 commit comments

Comments
 (0)