Skip to content

Commit 1d19a08

Browse files
authored
Format the last expression-statement as expression (#3631)
1 parent 84c2356 commit 1d19a08

File tree

11 files changed

+315
-87
lines changed

11 files changed

+315
-87
lines changed

src/expr.rs

+1-33
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use crate::types::{rewrite_path, PathContext};
3333
use crate::utils::{
3434
colon_spaces, contains_skip, count_newlines, first_line_ends_with, inner_attributes,
3535
last_line_extendable, last_line_width, mk_sp, outer_attributes, ptr_vec_to_ref_vec,
36-
semicolon_for_expr, semicolon_for_stmt, unicode_str_width, wrap_str,
36+
semicolon_for_expr, unicode_str_width, wrap_str,
3737
};
3838
use crate::vertical::rewrite_with_alignment;
3939
use crate::visitor::FmtVisitor;
@@ -568,28 +568,6 @@ fn rewrite_block(
568568
result
569569
}
570570

571-
impl Rewrite for ast::Stmt {
572-
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
573-
skip_out_of_file_lines_range!(context, self.span());
574-
575-
let result = match self.node {
576-
ast::StmtKind::Local(ref local) => local.rewrite(context, shape),
577-
ast::StmtKind::Expr(ref ex) | ast::StmtKind::Semi(ref ex) => {
578-
let suffix = if semicolon_for_stmt(context, self) {
579-
";"
580-
} else {
581-
""
582-
};
583-
584-
let shape = shape.sub_width(suffix.len())?;
585-
format_expr(ex, ExprType::Statement, context, shape).map(|s| s + suffix)
586-
}
587-
ast::StmtKind::Mac(..) | ast::StmtKind::Item(..) => None,
588-
};
589-
result.and_then(|res| recover_comment_removed(res, self.span(), context))
590-
}
591-
}
592-
593571
// Rewrite condition if the given expression has one.
594572
pub(crate) fn rewrite_cond(
595573
context: &RewriteContext<'_>,
@@ -1189,16 +1167,6 @@ pub(crate) fn stmt_is_expr(stmt: &ast::Stmt) -> bool {
11891167
}
11901168
}
11911169

1192-
pub(crate) fn stmt_is_if(stmt: &ast::Stmt) -> bool {
1193-
match stmt.node {
1194-
ast::StmtKind::Expr(ref e) => match e.node {
1195-
ast::ExprKind::If(..) => true,
1196-
_ => false,
1197-
},
1198-
_ => false,
1199-
}
1200-
}
1201-
12021170
pub(crate) fn is_unsafe_block(block: &ast::Block) -> bool {
12031171
if let ast::BlockCheckMode::Unsafe(..) = block.rules {
12041172
true

src/items.rs

+4-16
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ use crate::comment::{
1818
use crate::config::lists::*;
1919
use crate::config::{BraceStyle, Config, IndentStyle, Version};
2020
use crate::expr::{
21-
format_expr, is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, rewrite_assign_rhs_with,
22-
ExprType, RhsTactics,
21+
is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, rewrite_assign_rhs_with, RhsTactics,
2322
};
2423
use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
2524
use crate::macros::{rewrite_macro, MacroPosition};
@@ -28,6 +27,7 @@ use crate::rewrite::{Rewrite, RewriteContext};
2827
use crate::shape::{Indent, Shape};
2928
use crate::source_map::{LineRangeUtils, SpanUtils};
3029
use crate::spanned::Spanned;
30+
use crate::stmt::Stmt;
3131
use crate::utils::*;
3232
use crate::vertical::rewrite_with_alignment;
3333
use crate::visitor::FmtVisitor;
@@ -394,20 +394,8 @@ impl<'a> FmtVisitor<'a> {
394394
return None;
395395
}
396396

397-
let stmt = block.stmts.first()?;
398-
let res = match stmt_expr(stmt) {
399-
Some(e) => {
400-
let suffix = if semicolon_for_expr(&self.get_context(), e) {
401-
";"
402-
} else {
403-
""
404-
};
405-
406-
format_expr(e, ExprType::Statement, &self.get_context(), self.shape())
407-
.map(|s| s + suffix)?
408-
}
409-
None => stmt.rewrite(&self.get_context(), self.shape())?,
410-
};
397+
let res = Stmt::from_ast_node(block.stmts.first()?, true)
398+
.rewrite(&self.get_context(), self.shape())?;
411399

412400
let width = self.block_indent.width() + fn_str.len() + res.len() + 5;
413401
if !res.contains('\n') && width <= self.config.max_width() {

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ mod shape;
7272
pub(crate) mod source_file;
7373
pub(crate) mod source_map;
7474
mod spanned;
75+
mod stmt;
7576
mod string;
7677
#[cfg(test)]
7778
mod test;

src/stmt.rs

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
use syntax::ast;
2+
use syntax_pos::Span;
3+
4+
use crate::comment::recover_comment_removed;
5+
use crate::config::Version;
6+
use crate::expr::{format_expr, ExprType};
7+
use crate::rewrite::{Rewrite, RewriteContext};
8+
use crate::shape::Shape;
9+
use crate::source_map::LineRangeUtils;
10+
use crate::spanned::Spanned;
11+
use crate::utils::semicolon_for_stmt;
12+
13+
pub(crate) struct Stmt<'a> {
14+
inner: &'a ast::Stmt,
15+
is_last: bool,
16+
}
17+
18+
impl<'a> Spanned for Stmt<'a> {
19+
fn span(&self) -> Span {
20+
self.inner.span()
21+
}
22+
}
23+
24+
impl<'a> Stmt<'a> {
25+
pub(crate) fn as_ast_node(&self) -> &ast::Stmt {
26+
self.inner
27+
}
28+
29+
pub(crate) fn to_item(&self) -> Option<&ast::Item> {
30+
match self.inner.node {
31+
ast::StmtKind::Item(ref item) => Some(&**item),
32+
_ => None,
33+
}
34+
}
35+
36+
pub(crate) fn from_ast_node(inner: &'a ast::Stmt, is_last: bool) -> Self {
37+
Stmt { inner, is_last }
38+
}
39+
40+
pub(crate) fn from_ast_nodes<I>(iter: I) -> Vec<Self>
41+
where
42+
I: Iterator<Item = &'a ast::Stmt>,
43+
{
44+
let mut result = vec![];
45+
let mut iter = iter.peekable();
46+
while iter.peek().is_some() {
47+
result.push(Stmt {
48+
inner: iter.next().unwrap(),
49+
is_last: iter.peek().is_none(),
50+
})
51+
}
52+
result
53+
}
54+
55+
fn is_last_expr(&self) -> bool {
56+
if !self.is_last {
57+
return false;
58+
}
59+
60+
match self.as_ast_node().node {
61+
ast::StmtKind::Expr(ref expr) => match expr.node {
62+
ast::ExprKind::Ret(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Break(..) => {
63+
false
64+
}
65+
_ => true,
66+
},
67+
_ => false,
68+
}
69+
}
70+
}
71+
72+
impl<'a> Rewrite for Stmt<'a> {
73+
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
74+
let expr_type = if context.config.version() == Version::Two && self.is_last_expr() {
75+
ExprType::SubExpression
76+
} else {
77+
ExprType::Statement
78+
};
79+
format_stmt(context, shape, self.as_ast_node(), expr_type)
80+
}
81+
}
82+
83+
impl Rewrite for ast::Stmt {
84+
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
85+
format_stmt(context, shape, self, ExprType::Statement)
86+
}
87+
}
88+
89+
fn format_stmt(
90+
context: &RewriteContext<'_>,
91+
shape: Shape,
92+
stmt: &ast::Stmt,
93+
expr_type: ExprType,
94+
) -> Option<String> {
95+
skip_out_of_file_lines_range!(context, stmt.span());
96+
97+
let result = match stmt.node {
98+
ast::StmtKind::Local(ref local) => local.rewrite(context, shape),
99+
ast::StmtKind::Expr(ref ex) | ast::StmtKind::Semi(ref ex) => {
100+
let suffix = if semicolon_for_stmt(context, stmt) {
101+
";"
102+
} else {
103+
""
104+
};
105+
106+
let shape = shape.sub_width(suffix.len())?;
107+
format_expr(ex, expr_type, context, shape).map(|s| s + suffix)
108+
}
109+
ast::StmtKind::Mac(..) | ast::StmtKind::Item(..) => None,
110+
};
111+
result.and_then(|res| recover_comment_removed(res, stmt.span(), context))
112+
}

src/visitor.rs

+25-38
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ use syntax::{ast, visit};
77
use crate::attr::*;
88
use crate::comment::{CodeCharKind, CommentCodeSlices};
99
use crate::config::file_lines::FileName;
10-
use crate::config::{BraceStyle, Config, Version};
11-
use crate::expr::{format_expr, ExprType};
10+
use crate::config::{BraceStyle, Config};
1211
use crate::items::{
1312
format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item,
1413
rewrite_associated_impl_type, rewrite_associated_type, rewrite_existential_impl_type,
@@ -20,6 +19,7 @@ use crate::rewrite::{Rewrite, RewriteContext};
2019
use crate::shape::{Indent, Shape};
2120
use crate::source_map::{LineRangeUtils, SpanUtils};
2221
use crate::spanned::Spanned;
22+
use crate::stmt::Stmt;
2323
use crate::utils::{
2424
self, contains_skip, count_newlines, depr_skip_annotation, get_skip_macro_names,
2525
inner_attributes, mk_sp, ptr_vec_to_ref_vec, rewrite_ident, stmt_expr,
@@ -89,23 +89,27 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
8989
Shape::indented(self.block_indent, self.config)
9090
}
9191

92-
fn visit_stmt(&mut self, stmt: &ast::Stmt) {
92+
fn visit_stmt(&mut self, stmt: &Stmt<'_>) {
9393
debug!(
9494
"visit_stmt: {:?} {:?}",
95-
self.source_map.lookup_char_pos(stmt.span.lo()),
96-
self.source_map.lookup_char_pos(stmt.span.hi())
95+
self.source_map.lookup_char_pos(stmt.span().lo()),
96+
self.source_map.lookup_char_pos(stmt.span().hi())
9797
);
9898

99-
match stmt.node {
99+
match stmt.as_ast_node().node {
100100
ast::StmtKind::Item(ref item) => {
101101
self.visit_item(item);
102102
// Handle potential `;` after the item.
103-
self.format_missing(stmt.span.hi());
103+
self.format_missing(stmt.span().hi());
104104
}
105105
ast::StmtKind::Local(..) | ast::StmtKind::Expr(..) | ast::StmtKind::Semi(..) => {
106-
let attrs = get_attrs_from_stmt(stmt);
106+
let attrs = get_attrs_from_stmt(stmt.as_ast_node());
107107
if contains_skip(attrs) {
108-
self.push_skipped_with_span(attrs, stmt.span(), get_span_without_attrs(stmt));
108+
self.push_skipped_with_span(
109+
attrs,
110+
stmt.span(),
111+
get_span_without_attrs(stmt.as_ast_node()),
112+
);
109113
} else {
110114
let shape = self.shape();
111115
let rewrite = self.with_context(|ctx| stmt.rewrite(&ctx, shape));
@@ -115,11 +119,15 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
115119
ast::StmtKind::Mac(ref mac) => {
116120
let (ref mac, _macro_style, ref attrs) = **mac;
117121
if self.visit_attrs(attrs, ast::AttrStyle::Outer) {
118-
self.push_skipped_with_span(attrs, stmt.span(), get_span_without_attrs(stmt));
122+
self.push_skipped_with_span(
123+
attrs,
124+
stmt.span(),
125+
get_span_without_attrs(stmt.as_ast_node()),
126+
);
119127
} else {
120128
self.visit_mac(mac, None, MacroPosition::Statement);
121129
}
122-
self.format_missing(stmt.span.hi());
130+
self.format_missing(stmt.span().hi());
123131
}
124132
}
125133
}
@@ -717,50 +725,29 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
717725
self.visit_items_with_reordering(&ptr_vec_to_ref_vec(&m.items));
718726
}
719727

720-
fn walk_stmts(&mut self, stmts: &[ast::Stmt]) {
721-
fn to_stmt_item(stmt: &ast::Stmt) -> Option<&ast::Item> {
722-
match stmt.node {
723-
ast::StmtKind::Item(ref item) => Some(&**item),
724-
_ => None,
725-
}
726-
}
727-
728+
fn walk_stmts(&mut self, stmts: &[Stmt<'_>]) {
728729
if stmts.is_empty() {
729730
return;
730731
}
731732

732733
// Extract leading `use ...;`.
733734
let items: Vec<_> = stmts
734735
.iter()
735-
.take_while(|stmt| to_stmt_item(stmt).map_or(false, is_use_item))
736-
.filter_map(|stmt| to_stmt_item(stmt))
736+
.take_while(|stmt| stmt.to_item().map_or(false, is_use_item))
737+
.filter_map(|stmt| stmt.to_item())
737738
.collect();
738739

739740
if items.is_empty() {
740-
// The `if` expression at the end of the block should be formatted in a single
741-
// line if possible.
742-
if self.config.version() == Version::Two
743-
&& stmts.len() == 1
744-
&& crate::expr::stmt_is_if(&stmts[0])
745-
&& !contains_skip(get_attrs_from_stmt(&stmts[0]))
746-
{
747-
let shape = self.shape();
748-
let rewrite = self.with_context(|ctx| {
749-
format_expr(stmt_expr(&stmts[0])?, ExprType::SubExpression, ctx, shape)
750-
});
751-
self.push_rewrite(stmts[0].span(), rewrite);
752-
} else {
753-
self.visit_stmt(&stmts[0]);
754-
self.walk_stmts(&stmts[1..]);
755-
}
741+
self.visit_stmt(&stmts[0]);
742+
self.walk_stmts(&stmts[1..]);
756743
} else {
757744
self.visit_items_with_reordering(&items);
758745
self.walk_stmts(&stmts[items.len()..]);
759746
}
760747
}
761748

762749
fn walk_block_stmts(&mut self, b: &ast::Block) {
763-
self.walk_stmts(&b.stmts)
750+
self.walk_stmts(&Stmt::from_ast_nodes(b.stmts.iter()))
764751
}
765752

766753
fn format_mod(

tests/source/fn-single-line.rs renamed to tests/source/fn-single-line/version_one.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// rustfmt-fn_single_line: true
2+
// rustfmt-version: One
23
// Test single-line functions.
34

45
fn foo_expr() {

0 commit comments

Comments
 (0)