]> git.lizzy.rs Git - rust.git/commitdiff
Handle special-case macros
authortopecongiro <seuchida@gmail.com>
Fri, 1 Dec 2017 04:30:04 +0000 (13:30 +0900)
committerSeiichi Uchida <seuchida@gmail.com>
Sun, 3 Dec 2017 02:34:18 +0000 (11:34 +0900)
src/expr.rs
src/lists.rs

index ce2ea65b65aaade761d7a37d67c5d4e26413122e..70363f7dd23115be4f6a1ed1a1f5d5b04fab6fa0 100644 (file)
@@ -1862,9 +1862,6 @@ pub fn rewrite_call_inner<'a, T>(
     };
     let used_width = extra_offset(callee_str, shape);
     let one_line_width = shape.width.checked_sub(used_width + 2 * paren_overhead)?;
-    // 1 = "("
-    let combine_arg_with_callee =
-        callee_str.len() + 1 <= context.config.tab_spaces() && args.len() == 1;
 
     // 1 = "(" or ")"
     let one_line_shape = shape
@@ -1889,7 +1886,7 @@ pub fn rewrite_call_inner<'a, T>(
         one_line_width,
         args_max_width,
         force_trailing_comma,
-        combine_arg_with_callee,
+        callee_str,
     )?;
 
     if !context.use_block_indent() && need_block_indent(&list_str, nested_shape) && !extendable {
@@ -1930,7 +1927,7 @@ fn rewrite_call_args<'a, T>(
     one_line_width: usize,
     args_max_width: usize,
     force_trailing_comma: bool,
-    combine_arg_with_callee: bool,
+    callee_str: &str,
 ) -> Option<(bool, String)>
 where
     T: Rewrite + Spanned + ToExpr + 'a,
@@ -1960,7 +1957,7 @@ fn rewrite_call_args<'a, T>(
         nested_shape,
         one_line_width,
         args_max_width,
-        combine_arg_with_callee,
+        callee_str,
     );
 
     let fmt = ListFormatting {
@@ -1980,7 +1977,8 @@ fn rewrite_call_args<'a, T>(
         config: context.config,
     };
 
-    write_list(&item_vec, &fmt).map(|args_str| (tactic != DefinitiveListTactic::Vertical, args_str))
+    write_list(&item_vec, &fmt)
+        .map(|args_str| (tactic == DefinitiveListTactic::Horizontal, args_str))
 }
 
 fn try_overflow_last_arg<'a, T>(
@@ -1991,11 +1989,14 @@ fn try_overflow_last_arg<'a, T>(
     nested_shape: Shape,
     one_line_width: usize,
     args_max_width: usize,
-    combine_arg_with_callee: bool,
+    callee_str: &str,
 ) -> DefinitiveListTactic
 where
     T: Rewrite + Spanned + ToExpr + 'a,
 {
+    // 1 = "("
+    let combine_arg_with_callee =
+        callee_str.len() + 1 <= context.config.tab_spaces() && args.len() == 1;
     let overflow_last = combine_arg_with_callee || can_be_overflowed(context, args);
 
     // Replace the last item with its first line to see if it fits with
@@ -2032,6 +2033,16 @@ fn try_overflow_last_arg<'a, T>(
         _ if args.len() >= 1 => {
             item_vec[args.len() - 1].item = args.last()
                 .and_then(|last_arg| last_arg.rewrite(context, nested_shape));
+
+            let default_tactic = || {
+                definitive_tactic(
+                    &*item_vec,
+                    ListTactic::LimitedHorizontalVertical(args_max_width),
+                    Separator::Comma,
+                    one_line_width,
+                )
+            };
+
             // Use horizontal layout for a function with a single argument as long as
             // everything fits in a single line.
             if args.len() == 1
@@ -2042,12 +2053,44 @@ fn try_overflow_last_arg<'a, T>(
             {
                 tactic = DefinitiveListTactic::Horizontal;
             } else {
-                tactic = definitive_tactic(
-                    &*item_vec,
-                    ListTactic::LimitedHorizontalVertical(args_max_width),
-                    Separator::Comma,
-                    one_line_width,
-                );
+                tactic = default_tactic();
+                let is_simple_enough =
+                    tactic == DefinitiveListTactic::Vertical && is_every_args_simple(args);
+                if is_simple_enough
+                    && FORMAT_LIKE_WHITELIST
+                        .iter()
+                        .find(|s| **s == callee_str)
+                        .is_some()
+                {
+                    let args_tactic = definitive_tactic(
+                        &item_vec[1..],
+                        ListTactic::HorizontalVertical,
+                        Separator::Comma,
+                        nested_shape.width,
+                    );
+                    tactic = if args_tactic == DefinitiveListTactic::Horizontal {
+                        DefinitiveListTactic::FormatCall
+                    } else {
+                        default_tactic()
+                    };
+                } else if is_simple_enough && item_vec.len() >= 2
+                    && WRITE_LIKE_WHITELIST
+                        .iter()
+                        .find(|s| **s == callee_str)
+                        .is_some()
+                {
+                    let args_tactic = definitive_tactic(
+                        &item_vec[2..],
+                        ListTactic::HorizontalVertical,
+                        Separator::Comma,
+                        nested_shape.width,
+                    );
+                    tactic = if args_tactic == DefinitiveListTactic::Horizontal {
+                        DefinitiveListTactic::WriteCall
+                    } else {
+                        default_tactic()
+                    };
+                }
             }
         }
         _ => (),
@@ -2056,6 +2099,30 @@ fn try_overflow_last_arg<'a, T>(
     tactic
 }
 
+fn is_simple_arg(expr: &ast::Expr) -> bool {
+    match expr.node {
+        ast::ExprKind::Lit(..) => true,
+        ast::ExprKind::Path(ref qself, ref path) => qself.is_none() && path.segments.len() <= 1,
+        ast::ExprKind::AddrOf(_, ref expr)
+        | ast::ExprKind::Box(ref expr)
+        | ast::ExprKind::Cast(ref expr, _)
+        | ast::ExprKind::Field(ref expr, _)
+        | ast::ExprKind::Try(ref expr)
+        | ast::ExprKind::TupField(ref expr, _)
+        | ast::ExprKind::Unary(_, ref expr) => is_simple_arg(expr),
+        ast::ExprKind::Index(ref lhs, ref rhs) | ast::ExprKind::Repeat(ref lhs, ref rhs) => {
+            is_simple_arg(lhs) && is_simple_arg(rhs)
+        }
+        _ => false,
+    }
+}
+
+fn is_every_args_simple<T: ToExpr>(lists: &[&T]) -> bool {
+    lists
+        .iter()
+        .all(|arg| arg.to_expr().map_or(false, is_simple_arg))
+}
+
 /// Returns a shape for the last argument which is going to be overflowed.
 fn last_arg_shape<T>(
     lists: &[&T],
index f3e1c362dc1713c95e42fbbe63089e87328c5f7f..a51653b3732ae37a7404d5c028d7863a0bc33e30 100644 (file)
@@ -160,6 +160,10 @@ pub enum DefinitiveListTactic {
     Vertical,
     Horizontal,
     Mixed,
+    // Special case tactic for `format!()` variants.
+    FormatCall,
+    // Special case tactic for `write!()` varianta.
+    WriteCall,
 }
 
 impl DefinitiveListTactic {
@@ -267,7 +271,7 @@ pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
     I: IntoIterator<Item = T> + Clone,
     T: AsRef<ListItem>,
 {
-    let tactic = formatting.tactic;
+    let mut tactic = formatting.tactic;
     let sep_len = formatting.separator.len();
 
     // Now that we know how we will layout, we can decide for sure if there
@@ -309,6 +313,28 @@ pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
             DefinitiveListTactic::Horizontal if !first => {
                 result.push(' ');
             }
+            DefinitiveListTactic::FormatCall if !first => {
+                result.push('\n');
+                result.push_str(indent_str);
+                tactic = DefinitiveListTactic::Horizontal;
+            }
+            DefinitiveListTactic::WriteCall => {
+                let second = i == 1;
+                let third = i == 2;
+
+                if first {
+                    // Nothing
+                } else if second {
+                    result.push('\n');
+                    result.push_str(indent_str);
+                } else if third {
+                    result.push('\n');
+                    result.push_str(indent_str);
+                    tactic = DefinitiveListTactic::Horizontal;
+                } else {
+                    unreachable!();
+                }
+            }
             DefinitiveListTactic::Vertical if !first => {
                 result.push('\n');
                 result.push_str(indent_str);