Skip to content

Commit e910519

Browse files
committed
Overflow the last rhs of a 'simple' binary expr
1 parent d1ab3be commit e910519

File tree

5 files changed

+70
-1
lines changed

5 files changed

+70
-1
lines changed

src/expr.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ pub enum ExprType {
5050
SubExpression,
5151
}
5252

53+
fn is_nested_binary(context: &RewriteContext, expr: &ast::Expr) -> bool {
54+
if let ast::ExprKind::Binary(op, ..) = expr.node {
55+
if let Some(upper_op) = *context.upper_binop.borrow() {
56+
op.node == upper_op
57+
} else {
58+
false
59+
}
60+
} else {
61+
false
62+
}
63+
}
64+
5365
pub fn format_expr(
5466
expr: &ast::Expr,
5567
expr_type: ExprType,
@@ -62,6 +74,9 @@ pub fn format_expr(
6274
return Some(context.snippet(expr.span()).to_owned());
6375
}
6476

77+
let is_nested_binary = is_nested_binary(context, expr);
78+
context.set_upper_binop(expr);
79+
6580
let expr_rw = match expr.node {
6681
ast::ExprKind::Array(ref expr_vec) => rewrite_array(
6782
&ptr_vec_to_ref_vec(expr_vec),
@@ -89,6 +104,7 @@ pub fn format_expr(
89104
context,
90105
shape,
91106
context.config.binop_separator(),
107+
is_nested_binary,
92108
)
93109
}
94110
ast::ExprKind::Unary(ref op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape),
@@ -201,6 +217,7 @@ pub fn format_expr(
201217
context,
202218
shape,
203219
SeparatorPlace::Front,
220+
false,
204221
),
205222
ast::ExprKind::Type(ref expr, ref ty) => rewrite_pair(
206223
&**expr,
@@ -209,6 +226,7 @@ pub fn format_expr(
209226
context,
210227
shape,
211228
SeparatorPlace::Back,
229+
false,
212230
),
213231
ast::ExprKind::Index(ref expr, ref index) => {
214232
rewrite_index(&**expr, &**index, context, shape)
@@ -226,6 +244,7 @@ pub fn format_expr(
226244
context,
227245
shape,
228246
SeparatorPlace::Back,
247+
false,
229248
)
230249
}
231250
ast::ExprKind::Range(ref lhs, ref rhs, limits) => {
@@ -262,6 +281,7 @@ pub fn format_expr(
262281
context,
263282
shape,
264283
context.config.binop_separator(),
284+
false,
265285
)
266286
}
267287
(None, Some(rhs)) => {
@@ -323,17 +343,34 @@ pub struct PairParts<'a> {
323343
suffix: &'a str,
324344
}
325345

346+
/// Returns true if the given expression is a chain with 0 or more prefixes or
347+
/// suffixes (e.g. `&x.y`, `x.y.z()?` or `x.0 as usize`).
348+
fn is_chain(expr: &ast::Expr) -> bool {
349+
match expr.node {
350+
ast::ExprKind::AddrOf(_, ref expr)
351+
| ast::ExprKind::Box(ref expr)
352+
| ast::ExprKind::Try(ref expr)
353+
| ast::ExprKind::Unary(_, ref expr)
354+
| ast::ExprKind::Cast(ref expr, _) => is_chain(expr),
355+
ast::ExprKind::MethodCall(..) | ast::ExprKind::Field(..) | ast::ExprKind::TupField(..) => {
356+
true
357+
}
358+
_ => false,
359+
}
360+
}
361+
326362
pub fn rewrite_pair<LHS, RHS>(
327363
lhs: &LHS,
328364
rhs: &RHS,
329365
pp: PairParts,
330366
context: &RewriteContext,
331367
shape: Shape,
332368
separator_place: SeparatorPlace,
369+
is_nested_binary: bool,
333370
) -> Option<String>
334371
where
335372
LHS: Rewrite,
336-
RHS: Rewrite,
373+
RHS: ToExpr + Rewrite,
337374
{
338375
let lhs_overhead = match separator_place {
339376
SeparatorPlace::Back => shape.used_width() + pp.prefix.len() + pp.infix.trim_right().len(),
@@ -392,6 +429,20 @@ where
392429
rhs_shape = rhs_shape.offset_left(infix.len())?;
393430
}
394431
let rhs_result = rhs.rewrite(context, rhs_shape)?;
432+
// Put the rhs on the same line as the lhs if:
433+
// 1. it is not inside the other binary expression
434+
// 2. the lhs fits in a single line
435+
// 3. putting the rhs on the next line needs multiple lines as well
436+
if !is_nested_binary && !lhs_result.contains('\n') && rhs_result.contains('\n') {
437+
if let Some(ref orig_rhs_result) = rhs_orig_result {
438+
if rhs.to_expr().map_or(false, is_chain) {
439+
return Some(format!(
440+
"{}{}{}{}",
441+
lhs_result, pp.infix, orig_rhs_result, pp.suffix
442+
));
443+
}
444+
}
445+
}
395446
let indent_str = rhs_shape.indent.to_string_with_newline(context.config);
396447
let infix_with_sep = match separator_place {
397448
SeparatorPlace::Back => format!("{}{}", infix, indent_str),

src/patterns.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ impl Rewrite for Pat {
7878
context,
7979
shape,
8080
SeparatorPlace::Front,
81+
false,
8182
)
8283
}
8384
PatKind::Ref(ref pat, mutability) => {

src/rewrite.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,16 @@
1010

1111
// A generic trait to abstract the rewriting of an element (of the AST).
1212

13+
use syntax::ast;
1314
use syntax::codemap::{CodeMap, Span};
1415
use syntax::parse::ParseSess;
1516

1617
use config::{Config, IndentStyle};
1718
use shape::Shape;
1819
use visitor::SnippetProvider;
1920

21+
use std::cell::RefCell;
22+
2023
pub trait Rewrite {
2124
/// Rewrite self into shape.
2225
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String>;
@@ -36,6 +39,8 @@ pub struct RewriteContext<'a> {
3639
// When rewriting chain, veto going multi line except the last element
3740
pub force_one_line_chain: bool,
3841
pub snippet_provider: &'a SnippetProvider<'a>,
42+
// Holds a binary operator of the parent AST node if is a binary expression.
43+
pub upper_binop: RefCell<Option<ast::BinOpKind>>,
3944
}
4045

4146
impl<'a> RewriteContext<'a> {
@@ -51,4 +56,12 @@ impl<'a> RewriteContext<'a> {
5156
pub fn budget(&self, used_width: usize) -> usize {
5257
self.config.max_width().checked_sub(used_width).unwrap_or(0)
5358
}
59+
60+
pub fn set_upper_binop(&self, expr: &ast::Expr) {
61+
if let ast::ExprKind::Binary(op, ..) = expr.node {
62+
self.upper_binop.replace(Some(op.node));
63+
} else {
64+
self.upper_binop.replace(None);
65+
}
66+
}
5467
}

src/types.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ impl Rewrite for ast::Ty {
708708
context,
709709
shape,
710710
SeparatorPlace::Back,
711+
false,
711712
)
712713
}
713714
ast::TyKind::Infer => {

src/visitor.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ use shape::{Indent, Shape};
2626
use spanned::Spanned;
2727
use utils::{self, contains_skip, count_newlines, inner_attributes, mk_sp, ptr_vec_to_ref_vec};
2828

29+
use std::cell::RefCell;
30+
2931
/// Creates a string slice corresponding to the specified span.
3032
pub struct SnippetProvider<'a> {
3133
/// A pointer to the content of the file we are formatting.
@@ -695,6 +697,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
695697
is_if_else_block: false,
696698
force_one_line_chain: false,
697699
snippet_provider: self.snippet_provider,
700+
upper_binop: RefCell::new(None),
698701
}
699702
}
700703
}

0 commit comments

Comments
 (0)