Merge pull request #1729 from topecongiro/single-line-block

Allow single line block in expression context
This commit is contained in:
Nick Cameron 2017-06-21 08:33:12 +12:00 committed by GitHub
commit a4af0ec0e3
6 changed files with 185 additions and 93 deletions

View File

@ -79,7 +79,10 @@ fn from_matches(matches: &Matches) -> FmtResult<CliOptions> {
)); ));
} }
} else { } else {
println!("Warning: the default write-mode for Rustfmt will soon change to overwrite - this will not leave backups of changed files."); println!(
"Warning: the default write-mode for Rustfmt will soon change to overwrite \
- this will not leave backups of changed files."
);
} }
if let Some(ref file_lines) = matches.opt_str("file-lines") { if let Some(ref file_lines) = matches.opt_str("file-lines") {

View File

@ -42,7 +42,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
} }
#[derive(PartialEq)] #[derive(PartialEq)]
enum ExprType { pub enum ExprType {
Statement, Statement,
SubExpression, SubExpression,
} }
@ -67,7 +67,7 @@ fn combine_attr_and_expr(
format!("{}{}{}", attr_str, separator, expr_str) format!("{}{}{}", attr_str, separator, expr_str)
} }
fn format_expr( pub fn format_expr(
expr: &ast::Expr, expr: &ast::Expr,
expr_type: ExprType, expr_type: ExprType,
context: &RewriteContext, context: &RewriteContext,
@ -160,7 +160,23 @@ fn format_expr(
to_control_flow(expr, expr_type) to_control_flow(expr, expr_type)
.and_then(|control_flow| control_flow.rewrite(context, shape)) .and_then(|control_flow| control_flow.rewrite(context, shape))
} }
ast::ExprKind::Block(ref block) => block.rewrite(context, shape), ast::ExprKind::Block(ref block) => {
match expr_type {
ExprType::Statement => {
if is_unsafe_block(block) {
block.rewrite(context, shape)
} else {
// Rewrite block without trying to put it in a single line.
if let rw @ Some(_) = rewrite_empty_block(context, block, shape) {
return rw;
}
let prefix = try_opt!(block_prefix(context, block, shape));
rewrite_block_with_visitor(context, &prefix, block, shape)
}
}
ExprType::SubExpression => block.rewrite(context, shape),
}
}
ast::ExprKind::Match(ref cond, ref arms) => { ast::ExprKind::Match(ref cond, ref arms) => {
rewrite_match(context, cond, arms, shape, expr.span) rewrite_match(context, cond, arms, shape, expr.span)
} }
@ -290,7 +306,9 @@ fn format_expr(
) )
} }
ast::ExprKind::Catch(ref block) => { ast::ExprKind::Catch(ref block) => {
if let rewrite @ Some(_) = try_one_line_block(context, shape, "do catch ", block) { if let rewrite @ Some(_) =
rewrite_single_line_block(context, "do catch ", block, shape)
{
return rewrite; return rewrite;
} }
// 9 = `do catch ` // 9 = `do catch `
@ -315,23 +333,6 @@ fn format_expr(
} }
} }
fn try_one_line_block(
context: &RewriteContext,
shape: Shape,
prefix: &str,
block: &ast::Block,
) -> Option<String> {
if is_simple_block(block, context.codemap) {
let expr_shape = Shape::legacy(shape.width - prefix.len(), shape.indent);
let expr_str = try_opt!(block.stmts[0].rewrite(context, expr_shape));
let result = format!("{}{{ {} }}", prefix, expr_str);
if result.len() <= shape.width && !result.contains('\n') {
return Some(result);
}
}
None
}
pub fn rewrite_pair<LHS, RHS>( pub fn rewrite_pair<LHS, RHS>(
lhs: &LHS, lhs: &LHS,
rhs: &RHS, rhs: &RHS,
@ -763,44 +764,41 @@ fn nop_block_collapse(block_str: Option<String>, budget: usize) -> Option<String
}) })
} }
impl Rewrite for ast::Block { fn rewrite_empty_block(
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> { context: &RewriteContext,
// shape.width is used only for the single line case: either the empty block `{}`, block: &ast::Block,
// or an unsafe expression `unsafe { e }`. shape: Shape,
) -> Option<String> {
if self.stmts.is_empty() && !block_contains_comment(self, context.codemap) && if block.stmts.is_empty() && !block_contains_comment(block, context.codemap) &&
shape.width >= 2 shape.width >= 2
{ {
return Some("{}".to_owned()); return Some("{}".to_owned());
} }
// If a block contains only a single-line comment, then leave it on one line. // If a block contains only a single-line comment, then leave it on one line.
let user_str = context.snippet(self.span); let user_str = context.snippet(block.span);
let user_str = user_str.trim(); let user_str = user_str.trim();
if user_str.starts_with('{') && user_str.ends_with('}') { if user_str.starts_with('{') && user_str.ends_with('}') {
let comment_str = user_str[1..user_str.len() - 1].trim(); let comment_str = user_str[1..user_str.len() - 1].trim();
if self.stmts.is_empty() && !comment_str.contains('\n') && if block.stmts.is_empty() && !comment_str.contains('\n') &&
!comment_str.starts_with("//") && !comment_str.starts_with("//") && comment_str.len() + 4 <= shape.width
comment_str.len() + 4 <= shape.width
{ {
return Some(format!("{{ {} }}", comment_str)); return Some(format!("{{ {} }}", comment_str));
} }
} }
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config); None
visitor.block_indent = shape.indent; }
visitor.is_if_else_block = context.is_if_else_block;
let prefix = match self.rules { fn block_prefix(context: &RewriteContext, block: &ast::Block, shape: Shape) -> Option<String> {
Some(match block.rules {
ast::BlockCheckMode::Unsafe(..) => { ast::BlockCheckMode::Unsafe(..) => {
let snippet = context.snippet(self.span); let snippet = context.snippet(block.span);
let open_pos = try_opt!(snippet.find_uncommented("{")); let open_pos = try_opt!(snippet.find_uncommented("{"));
visitor.last_pos = self.span.lo + BytePos(open_pos as u32);
// Extract comment between unsafe and block start. // Extract comment between unsafe and block start.
let trimmed = &snippet[6..open_pos].trim(); let trimmed = &snippet[6..open_pos].trim();
let prefix = if !trimmed.is_empty() { if !trimmed.is_empty() {
// 9 = "unsafe {".len(), 7 = "unsafe ".len() // 9 = "unsafe {".len(), 7 = "unsafe ".len()
let budget = try_opt!(shape.width.checked_sub(9)); let budget = try_opt!(shape.width.checked_sub(9));
format!( format!(
@ -814,21 +812,54 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
) )
} else { } else {
"unsafe ".to_owned() "unsafe ".to_owned()
};
if let result @ Some(_) = try_one_line_block(context, shape, &prefix, self) {
return result;
} }
prefix
} }
ast::BlockCheckMode::Default => { ast::BlockCheckMode::Default => String::new(),
visitor.last_pos = self.span.lo; })
String::new()
} }
};
visitor.visit_block(self); fn rewrite_single_line_block(
context: &RewriteContext,
prefix: &str,
block: &ast::Block,
shape: Shape,
) -> Option<String> {
if is_simple_block(block, context.codemap) {
let expr_shape = Shape::legacy(shape.width - prefix.len(), shape.indent);
let expr_str = try_opt!(block.stmts[0].rewrite(context, expr_shape));
let result = format!("{}{{ {} }}", prefix, expr_str);
if result.len() <= shape.width && !result.contains('\n') {
return Some(result);
}
}
None
}
fn rewrite_block_with_visitor(
context: &RewriteContext,
prefix: &str,
block: &ast::Block,
shape: Shape,
) -> Option<String> {
if let rw @ Some(_) = rewrite_empty_block(context, block, shape) {
return rw;
}
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
visitor.block_indent = shape.indent;
visitor.is_if_else_block = context.is_if_else_block;
match block.rules {
ast::BlockCheckMode::Unsafe(..) => {
let snippet = context.snippet(block.span);
let open_pos = try_opt!(snippet.find_uncommented("{"));
visitor.last_pos = block.span.lo + BytePos(open_pos as u32)
}
ast::BlockCheckMode::Default => visitor.last_pos = block.span.lo,
}
visitor.visit_block(block);
if visitor.failed && shape.indent.alignment != 0 { if visitor.failed && shape.indent.alignment != 0 {
self.rewrite( block.rewrite(
context, context,
Shape::indented(shape.indent.block_only(), context.config), Shape::indented(shape.indent.block_only(), context.config),
) )
@ -836,6 +867,22 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
Some(format!("{}{}", prefix, visitor.buffer)) Some(format!("{}{}", prefix, visitor.buffer))
} }
} }
impl Rewrite for ast::Block {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
// shape.width is used only for the single line case: either the empty block `{}`,
// or an unsafe expression `unsafe { e }`.
if let rw @ Some(_) = rewrite_empty_block(context, self, shape) {
return rw;
}
let prefix = try_opt!(block_prefix(context, self, shape));
if let rw @ Some(_) = rewrite_single_line_block(context, &prefix, self, shape) {
return rw;
}
rewrite_block_with_visitor(context, &prefix, self, shape)
}
} }
impl Rewrite for ast::Stmt { impl Rewrite for ast::Stmt {
@ -1249,7 +1296,12 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
}; };
let mut block_context = context.clone(); let mut block_context = context.clone();
block_context.is_if_else_block = self.else_block.is_some(); block_context.is_if_else_block = self.else_block.is_some();
let block_str = try_opt!(self.block.rewrite(&block_context, block_shape)); let block_str = try_opt!(rewrite_block_with_visitor(
&block_context,
"",
self.block,
block_shape,
));
let mut result = format!("{}{}", cond_str, block_str); let mut result = format!("{}{}", cond_str, block_str);
@ -1291,7 +1343,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
width: min(1, shape.width), width: min(1, shape.width),
..shape ..shape
}; };
else_block.rewrite(context, else_shape) format_expr(else_block, ExprType::Statement, context, else_shape)
} }
}; };
@ -1658,7 +1710,10 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
.unwrap() .unwrap()
.sub_width(comma.len()) .sub_width(comma.len())
.unwrap(); .unwrap();
let rewrite = nop_block_collapse(body.rewrite(context, arm_shape), arm_shape.width); let rewrite = nop_block_collapse(
format_expr(body, ExprType::Statement, context, arm_shape),
arm_shape.width,
);
let is_block = if let ast::ExprKind::Block(..) = body.node { let is_block = if let ast::ExprKind::Block(..) = body.node {
true true
} else { } else {
@ -1693,7 +1748,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
// necessary. // necessary.
let body_shape = try_opt!(shape.block_left(context.config.tab_spaces())); let body_shape = try_opt!(shape.block_left(context.config.tab_spaces()));
let next_line_body = try_opt!(nop_block_collapse( let next_line_body = try_opt!(nop_block_collapse(
body.rewrite(context, body_shape), format_expr(body, ExprType::Statement, context, body_shape),
body_shape.width, body_shape.width,
)); ));
let indent_str = shape let indent_str = shape

View File

@ -17,7 +17,7 @@
trimmed_last_line_width, colon_spaces, mk_sp}; trimmed_last_line_width, colon_spaces, mk_sp};
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, list_helper, use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, list_helper,
DefinitiveListTactic, ListTactic, definitive_tactic}; DefinitiveListTactic, ListTactic, definitive_tactic};
use expr::{is_empty_block, is_simple_block_stmt, rewrite_assign_rhs}; use expr::{format_expr, is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, ExprType};
use comment::{FindUncommented, contains_comment, rewrite_comment, recover_comment_removed}; use comment::{FindUncommented, contains_comment, rewrite_comment, recover_comment_removed};
use visitor::FmtVisitor; use visitor::FmtVisitor;
use rewrite::{Rewrite, RewriteContext}; use rewrite::{Rewrite, RewriteContext};
@ -352,7 +352,9 @@ fn single_line_fn(&self, fn_str: &str, block: &ast::Block) -> Option<String> {
Some(e) => { Some(e) => {
let suffix = if semicolon_for_expr(e) { ";" } else { "" }; let suffix = if semicolon_for_expr(e) { ";" } else { "" };
e.rewrite( format_expr(
&e,
ExprType::Statement,
&self.get_context(), &self.get_context(),
Shape::indented(self.block_indent, self.config), Shape::indented(self.block_indent, self.config),
).map(|s| s + suffix) ).map(|s| s + suffix)

View File

@ -17,6 +17,7 @@
use strings::string_buffer::StringBuffer; use strings::string_buffer::StringBuffer;
use {Indent, Shape}; use {Indent, Shape};
use expr::{format_expr, ExprType};
use utils::{self, mk_sp}; use utils::{self, mk_sp};
use codemap::{LineRangeUtils, SpanUtils}; use codemap::{LineRangeUtils, SpanUtils};
use comment::{contains_comment, FindUncommented}; use comment::{contains_comment, FindUncommented};
@ -87,7 +88,20 @@ fn visit_stmt(&mut self, stmt: &ast::Stmt) {
); );
self.push_rewrite(stmt.span, rewrite); self.push_rewrite(stmt.span, rewrite);
} }
ast::StmtKind::Expr(ref expr) | ast::StmtKind::Expr(ref expr) => {
let rewrite = format_expr(
expr,
ExprType::Statement,
&self.get_context(),
Shape::indented(self.block_indent, self.config),
);
let span = if expr.attrs.is_empty() {
stmt.span
} else {
mk_sp(expr.attrs[0].span.lo, stmt.span.hi)
};
self.push_rewrite(span, rewrite)
}
ast::StmtKind::Semi(ref expr) => { ast::StmtKind::Semi(ref expr) => {
let rewrite = stmt.rewrite( let rewrite = stmt.rewrite(
&self.get_context(), &self.get_context(),

View File

@ -299,3 +299,12 @@ fn issue1106() {
.filter_entry(|entry| exclusions.filter_entry(entry)) { .filter_entry(|entry| exclusions.filter_entry(entry)) {
} }
} }
fn issue1570() {
a_very_long_function_name({some_func(1, {1})})
}
fn issue1714() {
v = &mut {v}[mid..];
let (left, right) = {v}.split_at_mut(mid);
}

View File

@ -358,3 +358,12 @@ fn issue1106() {
.filter_entry(|entry| exclusions.filter_entry(entry)) .filter_entry(|entry| exclusions.filter_entry(entry))
{} {}
} }
fn issue1570() {
a_very_long_function_name({ some_func(1, { 1 }) })
}
fn issue1714() {
v = &mut { v }[mid..];
let (left, right) = { v }.split_at_mut(mid);
}