Rollup merge of #131035 - dingxiangfei2009:tweak-if-let-rescope-lint, r=jieyouxu
Preserve brackets around if-lets and skip while-lets r? `@jieyouxu` Tracked by #124085 Fresh out of #129466, we have discovered 9 crates that the lint did not successfully migrate because the span of `if let` includes the surrounding brackets `(..)` like the following, which surprised me a bit. ```rust if (if let .. { .. } else { .. }) { // ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // the span somehow includes the surrounding brackets } ``` There is one crate that failed the migration because some suggestion spans cross the macro expansion boundaries. Surely there is no way to patch them with `match` rewrite. To handle this case, we will instead require all spans to be tested for admissibility as suggestion spans. Besides, there are 4 false negative cases discovered with desugared-`while let`. We don't need to lint them, because the `else` branch surely contains exactly one statement because the drop order is not changed whatsoever in this case. ```rust while let Some(value) = droppy().get() { .. } // is desugared into loop { if let Some(value) = droppy().get() { .. } else { break; // here can be nothing observable in this block } } ``` I believe this is the one and only false positive that I have found. I think we have finally nailed all the corner cases this time.
This commit is contained in:
commit
dc1ccc5264
4 changed files with 145 additions and 7 deletions
|
@ -122,7 +122,11 @@ impl IfLetRescope {
|
|||
}
|
||||
let tcx = cx.tcx;
|
||||
let source_map = tcx.sess.source_map();
|
||||
let expr_end = expr.span.shrink_to_hi();
|
||||
let expr_end = match expr.kind {
|
||||
hir::ExprKind::If(_cond, conseq, None) => conseq.span.shrink_to_hi(),
|
||||
hir::ExprKind::If(_cond, _conseq, Some(alt)) => alt.span.shrink_to_hi(),
|
||||
_ => return,
|
||||
};
|
||||
let mut add_bracket_to_match_head = match_head_needs_bracket(tcx, expr);
|
||||
let mut significant_droppers = vec![];
|
||||
let mut lifetime_ends = vec![];
|
||||
|
@ -145,7 +149,10 @@ impl IfLetRescope {
|
|||
recovered: Recovered::No,
|
||||
}) = cond.kind
|
||||
{
|
||||
let if_let_pat = expr.span.shrink_to_lo().between(init.span);
|
||||
// Peel off round braces
|
||||
let if_let_pat = source_map
|
||||
.span_take_while(expr.span, |&ch| ch == '(' || ch.is_whitespace())
|
||||
.between(init.span);
|
||||
// The consequent fragment is always a block.
|
||||
let before_conseq = conseq.span.shrink_to_lo();
|
||||
let lifetime_end = source_map.end_point(conseq.span);
|
||||
|
@ -159,6 +166,8 @@ impl IfLetRescope {
|
|||
if ty_ascription.is_some()
|
||||
|| !expr.span.can_be_used_for_suggestions()
|
||||
|| !pat.span.can_be_used_for_suggestions()
|
||||
|| !if_let_pat.can_be_used_for_suggestions()
|
||||
|| !before_conseq.can_be_used_for_suggestions()
|
||||
{
|
||||
// Our `match` rewrites does not support type ascription,
|
||||
// so we just bail.
|
||||
|
@ -240,6 +249,23 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
|
|||
if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) {
|
||||
return;
|
||||
}
|
||||
if let hir::ExprKind::Loop(block, _label, hir::LoopSource::While, _span) = expr.kind
|
||||
&& let Some(value) = block.expr
|
||||
&& let hir::ExprKind::If(cond, _conseq, _alt) = value.kind
|
||||
&& let hir::ExprKind::Let(..) = cond.kind
|
||||
{
|
||||
// Recall that `while let` is lowered into this:
|
||||
// ```
|
||||
// loop {
|
||||
// if let .. { body } else { break; }
|
||||
// }
|
||||
// ```
|
||||
// There is no observable change in drop order on the overall `if let` expression
|
||||
// given that the `{ break; }` block is trivial so the edition change
|
||||
// means nothing substantial to this `while` statement.
|
||||
self.skip.insert(value.hir_id);
|
||||
return;
|
||||
}
|
||||
if expr_parent_is_stmt(cx.tcx, expr.hir_id)
|
||||
&& matches!(expr.kind, hir::ExprKind::If(_cond, _conseq, None))
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue