diff --git a/src/expr.rs b/src/expr.rs index d4461293d60..068b8f7fed6 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -664,11 +664,7 @@ fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option &'static str { - if pats.is_empty() { - "" - } else { - "let" - } + if pats.is_empty() { "" } else { "let" } } impl<'a> ControlFlow<'a> { @@ -1182,6 +1178,16 @@ pub fn stmt_is_expr(stmt: &ast::Stmt) -> bool { } } +pub(crate) fn stmt_is_if(stmt: &ast::Stmt) -> bool { + match stmt.node { + ast::StmtKind::Expr(ref e) => match e.node { + ast::ExprKind::If(..) => true, + _ => false, + }, + _ => false, + } +} + pub fn is_unsafe_block(block: &ast::Block) -> bool { if let ast::BlockCheckMode::Unsafe(..) = block.rules { true diff --git a/src/visitor.rs b/src/visitor.rs index 0d350e66c1a..e1a440f3441 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -6,7 +6,8 @@ use syntax::{ast, visit}; use crate::attr::*; use crate::comment::{CodeCharKind, CommentCodeSlices, FindUncommented}; -use crate::config::{BraceStyle, Config}; +use crate::config::{BraceStyle, Config, Version}; +use crate::expr::{format_expr, ExprType}; use crate::items::{ format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_associated_impl_type, rewrite_associated_type, rewrite_existential_impl_type, @@ -20,7 +21,7 @@ use crate::source_map::{LineRangeUtils, SpanUtils}; use crate::spanned::Spanned; use crate::utils::{ self, contains_skip, count_newlines, inner_attributes, mk_sp, ptr_vec_to_ref_vec, - rewrite_ident, DEPR_SKIP_ANNOTATION, + rewrite_ident, stmt_expr, DEPR_SKIP_ANNOTATION, }; use crate::{ErrorKind, FormatReport, FormattingError}; @@ -177,7 +178,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { self.walk_block_stmts(b); if !b.stmts.is_empty() { - if let Some(expr) = utils::stmt_expr(&b.stmts[b.stmts.len() - 1]) { + if let Some(expr) = stmt_expr(&b.stmts[b.stmts.len() - 1]) { if utils::semicolon_for_expr(&self.get_context(), expr) { self.push_str(";"); } @@ -694,8 +695,22 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { .collect(); if items.is_empty() { - self.visit_stmt(&stmts[0]); - self.walk_stmts(&stmts[1..]); + // The `if` expression at the end of the block should be formatted in a single + // line if possible. + if self.config.version() == Version::Two + && stmts.len() == 1 + && crate::expr::stmt_is_if(&stmts[0]) + && !contains_skip(get_attrs_from_stmt(&stmts[0])) + { + let shape = self.shape(); + let rewrite = self.with_context(|ctx| { + format_expr(stmt_expr(&stmts[0])?, ExprType::SubExpression, ctx, shape) + }); + self.push_rewrite(stmts[0].span(), rewrite); + } else { + self.visit_stmt(&stmts[0]); + self.walk_stmts(&stmts[1..]); + } } else { self.visit_items_with_reordering(&items); self.walk_stmts(&stmts[items.len()..]); diff --git a/tests/source/one_line_if_v1.rs b/tests/source/one_line_if_v1.rs new file mode 100644 index 00000000000..d3dcbe6787a --- /dev/null +++ b/tests/source/one_line_if_v1.rs @@ -0,0 +1,42 @@ +// rustfmt-version: One + +fn plain_if(x: bool) -> u8 { + if x { + 0 + } else { + 1 + } +} + +fn paren_if(x: bool) -> u8 { + (if x { 0 } else { 1 }) +} + +fn let_if(x: bool) -> u8 { + let x = if x { + foo() + } else { + bar() + }; + x +} + +fn return_if(x: bool) -> u8 { + return if x { + 0 + } else { + 1 + }; +} + +fn multi_if() { + use std::io; + if x { foo() } else { bar() } + if x { foo() } else { bar() } +} + +fn middle_if() { + use std::io; + if x { foo() } else { bar() } + let x = 1; +} diff --git a/tests/source/one_line_if_v2.rs b/tests/source/one_line_if_v2.rs new file mode 100644 index 00000000000..40c834959f9 --- /dev/null +++ b/tests/source/one_line_if_v2.rs @@ -0,0 +1,42 @@ +// rustfmt-version: Two + +fn plain_if(x: bool) -> u8 { + if x { + 0 + } else { + 1 + } +} + +fn paren_if(x: bool) -> u8 { + (if x { 0 } else { 1 }) +} + +fn let_if(x: bool) -> u8 { + let x = if x { + foo() + } else { + bar() + }; + x +} + +fn return_if(x: bool) -> u8 { + return if x { + 0 + } else { + 1 + }; +} + +fn multi_if() { + use std::io; + if x { foo() } else { bar() } + if x { foo() } else { bar() } +} + +fn middle_if() { + use std::io; + if x { foo() } else { bar() } + let x = 1; +} diff --git a/tests/target/one_line_if_v1.rs b/tests/target/one_line_if_v1.rs new file mode 100644 index 00000000000..b3c6c4cbeb2 --- /dev/null +++ b/tests/target/one_line_if_v1.rs @@ -0,0 +1,46 @@ +// rustfmt-version: One + +fn plain_if(x: bool) -> u8 { + if x { + 0 + } else { + 1 + } +} + +fn paren_if(x: bool) -> u8 { + (if x { 0 } else { 1 }) +} + +fn let_if(x: bool) -> u8 { + let x = if x { foo() } else { bar() }; + x +} + +fn return_if(x: bool) -> u8 { + return if x { 0 } else { 1 }; +} + +fn multi_if() { + use std::io; + if x { + foo() + } else { + bar() + } + if x { + foo() + } else { + bar() + } +} + +fn middle_if() { + use std::io; + if x { + foo() + } else { + bar() + } + let x = 1; +} diff --git a/tests/target/one_line_if_v2.rs b/tests/target/one_line_if_v2.rs new file mode 100644 index 00000000000..81ca4c8b8b4 --- /dev/null +++ b/tests/target/one_line_if_v2.rs @@ -0,0 +1,38 @@ +// rustfmt-version: Two + +fn plain_if(x: bool) -> u8 { + if x { 0 } else { 1 } +} + +fn paren_if(x: bool) -> u8 { + (if x { 0 } else { 1 }) +} + +fn let_if(x: bool) -> u8 { + let x = if x { foo() } else { bar() }; + x +} + +fn return_if(x: bool) -> u8 { + return if x { 0 } else { 1 }; +} + +fn multi_if() { + use std::io; + if x { + foo() + } else { + bar() + } + if x { foo() } else { bar() } +} + +fn middle_if() { + use std::io; + if x { + foo() + } else { + bar() + } + let x = 1; +}