Skip to content

Commit 4018873

Browse files
authored
Merge pull request #2219 from topecongiro/issue-549
Handle special-case format! like macros
2 parents 07106d4 + 026c716 commit 4018873

File tree

11 files changed

+168
-59
lines changed

11 files changed

+168
-59
lines changed

src/chains.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,7 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
136136
};
137137
debug!(
138138
"child_shapes {:?} {:?}",
139-
first_child_shape,
140-
other_child_shape
139+
first_child_shape, other_child_shape
141140
);
142141

143142
let child_shape_iter = Some(first_child_shape)

src/checkstyle.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ where
5757
writer,
5858
"<error line=\"{}\" severity=\"warning\" message=\"Should be `{}`\" \
5959
/>",
60-
mismatch.line_number,
61-
message
60+
mismatch.line_number, message
6261
)?;
6362
}
6463
}

src/comment.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,7 @@ pub fn combine_strs_with_missing_comments(
205205
};
206206
Some(format!(
207207
"{}{}{}{}{}",
208-
prev_str,
209-
first_sep,
210-
missing_comment,
211-
second_sep,
212-
next_str,
208+
prev_str, first_sep, missing_comment, second_sep, next_str,
213209
))
214210
}
215211

src/config.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -714,8 +714,7 @@ mod test {
714714
toml,
715715
format!(
716716
"merge_derives = {}\nskip_children = {}\n",
717-
merge_derives,
718-
skip_children,
717+
merge_derives, skip_children,
719718
)
720719
);
721720
}

src/expr.rs

Lines changed: 108 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,7 @@ where
353353
if one_line_width <= shape.width {
354354
return Some(format!(
355355
"{}{}{}{}",
356-
lhs_result,
357-
pp.infix,
358-
rhs_result,
359-
pp.suffix
356+
lhs_result, pp.infix, rhs_result, pp.suffix
360357
));
361358
}
362359
}
@@ -390,10 +387,7 @@ where
390387
};
391388
Some(format!(
392389
"{}{}{}{}",
393-
lhs_result,
394-
infix_with_sep,
395-
rhs_result,
396-
pp.suffix
390+
lhs_result, infix_with_sep, rhs_result, pp.suffix
397391
))
398392
}
399393

@@ -883,10 +877,7 @@ impl<'a> ControlFlow<'a> {
883877

884878
let result = format!(
885879
"{} {} {{ {} }} else {{ {} }}",
886-
self.keyword,
887-
pat_expr_str,
888-
if_str,
889-
else_str
880+
self.keyword, pat_expr_str, if_str, else_str
890881
);
891882

892883
if result.len() <= width {
@@ -1589,10 +1580,7 @@ fn rewrite_match_body(
15891580

15901581
Some(format!(
15911582
"{} =>{}{}{}",
1592-
pats_str,
1593-
block_sep,
1594-
body_str,
1595-
body_suffix
1583+
pats_str, block_sep, body_str, body_suffix
15961584
))
15971585
};
15981586

@@ -1807,6 +1795,25 @@ fn rewrite_string_lit(context: &RewriteContext, span: Span, shape: Shape) -> Opt
18071795
)
18081796
}
18091797

1798+
const FORMAT_LIKE_WHITELIST: &[&str] = &[
1799+
// From the Rust Standard Library.
1800+
"eprint!",
1801+
"eprintln!",
1802+
"format!",
1803+
"format_args!",
1804+
"panic!",
1805+
"println!",
1806+
"unreachable!",
1807+
// From the `log` crate.
1808+
"debug!",
1809+
"error!",
1810+
"info!",
1811+
"panic!",
1812+
"warn!",
1813+
];
1814+
1815+
const WRITE_LIKE_WHITELIST: &[&str] = &["assert!", "write!", "writeln!"];
1816+
18101817
pub fn rewrite_call(
18111818
context: &RewriteContext,
18121819
callee: &str,
@@ -1850,9 +1857,6 @@ where
18501857
};
18511858
let used_width = extra_offset(callee_str, shape);
18521859
let one_line_width = shape.width.checked_sub(used_width + 2 * paren_overhead)?;
1853-
// 1 = "("
1854-
let combine_arg_with_callee =
1855-
callee_str.len() + 1 <= context.config.tab_spaces() && args.len() == 1;
18561860

18571861
// 1 = "(" or ")"
18581862
let one_line_shape = shape
@@ -1877,7 +1881,7 @@ where
18771881
one_line_width,
18781882
args_max_width,
18791883
force_trailing_comma,
1880-
combine_arg_with_callee,
1884+
callee_str,
18811885
)?;
18821886

18831887
if !context.use_block_indent() && need_block_indent(&list_str, nested_shape) && !extendable {
@@ -1918,7 +1922,7 @@ fn rewrite_call_args<'a, T>(
19181922
one_line_width: usize,
19191923
args_max_width: usize,
19201924
force_trailing_comma: bool,
1921-
combine_arg_with_callee: bool,
1925+
callee_str: &str,
19221926
) -> Option<(bool, String)>
19231927
where
19241928
T: Rewrite + Spanned + ToExpr + 'a,
@@ -1948,7 +1952,7 @@ where
19481952
nested_shape,
19491953
one_line_width,
19501954
args_max_width,
1951-
combine_arg_with_callee,
1955+
callee_str,
19521956
);
19531957

19541958
let fmt = ListFormatting {
@@ -1968,7 +1972,8 @@ where
19681972
config: context.config,
19691973
};
19701974

1971-
write_list(&item_vec, &fmt).map(|args_str| (tactic != DefinitiveListTactic::Vertical, args_str))
1975+
write_list(&item_vec, &fmt)
1976+
.map(|args_str| (tactic == DefinitiveListTactic::Horizontal, args_str))
19721977
}
19731978

19741979
fn try_overflow_last_arg<'a, T>(
@@ -1979,11 +1984,14 @@ fn try_overflow_last_arg<'a, T>(
19791984
nested_shape: Shape,
19801985
one_line_width: usize,
19811986
args_max_width: usize,
1982-
combine_arg_with_callee: bool,
1987+
callee_str: &str,
19831988
) -> DefinitiveListTactic
19841989
where
19851990
T: Rewrite + Spanned + ToExpr + 'a,
19861991
{
1992+
// 1 = "("
1993+
let combine_arg_with_callee =
1994+
callee_str.len() + 1 <= context.config.tab_spaces() && args.len() == 1;
19871995
let overflow_last = combine_arg_with_callee || can_be_overflowed(context, args);
19881996

19891997
// Replace the last item with its first line to see if it fits with
@@ -2020,6 +2028,16 @@ where
20202028
_ if args.len() >= 1 => {
20212029
item_vec[args.len() - 1].item = args.last()
20222030
.and_then(|last_arg| last_arg.rewrite(context, nested_shape));
2031+
2032+
let default_tactic = || {
2033+
definitive_tactic(
2034+
&*item_vec,
2035+
ListTactic::LimitedHorizontalVertical(args_max_width),
2036+
Separator::Comma,
2037+
one_line_width,
2038+
)
2039+
};
2040+
20232041
// Use horizontal layout for a function with a single argument as long as
20242042
// everything fits in a single line.
20252043
if args.len() == 1
@@ -2030,12 +2048,29 @@ where
20302048
{
20312049
tactic = DefinitiveListTactic::Horizontal;
20322050
} else {
2033-
tactic = definitive_tactic(
2034-
&*item_vec,
2035-
ListTactic::LimitedHorizontalVertical(args_max_width),
2036-
Separator::Comma,
2037-
one_line_width,
2038-
);
2051+
tactic = default_tactic();
2052+
2053+
// For special-case macros, we may want to use different tactics.
2054+
let maybe_args_offset = maybe_get_args_offset(callee_str, args);
2055+
2056+
if tactic == DefinitiveListTactic::Vertical && maybe_args_offset.is_some() {
2057+
let args_offset = maybe_args_offset.unwrap();
2058+
let args_tactic = definitive_tactic(
2059+
&item_vec[args_offset..],
2060+
ListTactic::HorizontalVertical,
2061+
Separator::Comma,
2062+
nested_shape.width,
2063+
);
2064+
2065+
// Every argument is simple and fits on a single line.
2066+
if args_tactic == DefinitiveListTactic::Horizontal {
2067+
tactic = if args_offset == 1 {
2068+
DefinitiveListTactic::FormatCall
2069+
} else {
2070+
DefinitiveListTactic::WriteCall
2071+
};
2072+
}
2073+
}
20392074
}
20402075
}
20412076
_ => (),
@@ -2044,6 +2079,49 @@ where
20442079
tactic
20452080
}
20462081

2082+
fn is_simple_arg(expr: &ast::Expr) -> bool {
2083+
match expr.node {
2084+
ast::ExprKind::Lit(..) => true,
2085+
ast::ExprKind::Path(ref qself, ref path) => qself.is_none() && path.segments.len() <= 1,
2086+
ast::ExprKind::AddrOf(_, ref expr)
2087+
| ast::ExprKind::Box(ref expr)
2088+
| ast::ExprKind::Cast(ref expr, _)
2089+
| ast::ExprKind::Field(ref expr, _)
2090+
| ast::ExprKind::Try(ref expr)
2091+
| ast::ExprKind::TupField(ref expr, _)
2092+
| ast::ExprKind::Unary(_, ref expr) => is_simple_arg(expr),
2093+
ast::ExprKind::Index(ref lhs, ref rhs) | ast::ExprKind::Repeat(ref lhs, ref rhs) => {
2094+
is_simple_arg(lhs) && is_simple_arg(rhs)
2095+
}
2096+
_ => false,
2097+
}
2098+
}
2099+
2100+
fn is_every_args_simple<T: ToExpr>(lists: &[&T]) -> bool {
2101+
lists
2102+
.iter()
2103+
.all(|arg| arg.to_expr().map_or(false, is_simple_arg))
2104+
}
2105+
2106+
/// In case special-case style is required, returns an offset from which we start horizontal layout.
2107+
fn maybe_get_args_offset<T: ToExpr>(callee_str: &str, args: &[&T]) -> Option<usize> {
2108+
if FORMAT_LIKE_WHITELIST
2109+
.iter()
2110+
.find(|s| **s == callee_str)
2111+
.is_some() && args.len() >= 1 && is_every_args_simple(args)
2112+
{
2113+
Some(1)
2114+
} else if WRITE_LIKE_WHITELIST
2115+
.iter()
2116+
.find(|s| **s == callee_str)
2117+
.is_some() && args.len() >= 2 && is_every_args_simple(args)
2118+
{
2119+
Some(2)
2120+
} else {
2121+
None
2122+
}
2123+
}
2124+
20472125
/// Returns a shape for the last argument which is going to be overflowed.
20482126
fn last_arg_shape<T>(
20492127
lists: &[&T],

src/items.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,7 @@ impl Rewrite for ast::Local {
4848
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
4949
debug!(
5050
"Local::rewrite {:?} {} {:?}",
51-
self,
52-
shape.width,
53-
shape.indent
51+
self, shape.width, shape.indent
5452
);
5553

5654
skip_out_of_file_lines_range!(context, self.span);
@@ -844,9 +842,7 @@ fn rewrite_trait_ref(
844842
if !(retry && trait_ref_str.contains('\n')) {
845843
return Some(format!(
846844
"{} {}{}",
847-
generics_str,
848-
polarity_str,
849-
&trait_ref_str
845+
generics_str, polarity_str, &trait_ref_str
850846
));
851847
}
852848
}
@@ -1842,9 +1838,7 @@ fn rewrite_fn_base(
18421838

18431839
debug!(
18441840
"rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, arg_indent: {:?}",
1845-
one_line_budget,
1846-
multi_line_budget,
1847-
arg_indent
1841+
one_line_budget, multi_line_budget, arg_indent
18481842
);
18491843

18501844
// Check if vertical layout was forced.

src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,7 @@ impl fmt::Display for ErrorKind {
9393
ErrorKind::LineOverflow(found, maximum) => write!(
9494
fmt,
9595
"line exceeded maximum width (maximum: {}, found: {})",
96-
maximum,
97-
found
96+
maximum, found
9897
),
9998
ErrorKind::TrailingWhitespace => write!(fmt, "left behind trailing whitespace"),
10099
ErrorKind::BadIssue(issue) => write!(fmt, "found {}", issue),

src/lists.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ pub enum DefinitiveListTactic {
160160
Vertical,
161161
Horizontal,
162162
Mixed,
163+
// Special case tactic for `format!()` variants.
164+
FormatCall,
165+
// Special case tactic for `write!()` varianta.
166+
WriteCall,
163167
}
164168

165169
impl DefinitiveListTactic {
@@ -267,7 +271,7 @@ where
267271
I: IntoIterator<Item = T> + Clone,
268272
T: AsRef<ListItem>,
269273
{
270-
let tactic = formatting.tactic;
274+
let mut tactic = formatting.tactic;
271275
let sep_len = formatting.separator.len();
272276

273277
// Now that we know how we will layout, we can decide for sure if there
@@ -309,6 +313,28 @@ where
309313
DefinitiveListTactic::Horizontal if !first => {
310314
result.push(' ');
311315
}
316+
DefinitiveListTactic::FormatCall if !first => {
317+
result.push('\n');
318+
result.push_str(indent_str);
319+
tactic = DefinitiveListTactic::Horizontal;
320+
}
321+
DefinitiveListTactic::WriteCall => {
322+
let second = i == 1;
323+
let third = i == 2;
324+
325+
if first {
326+
// Nothing
327+
} else if second {
328+
result.push('\n');
329+
result.push_str(indent_str);
330+
} else if third {
331+
result.push('\n');
332+
result.push_str(indent_str);
333+
tactic = DefinitiveListTactic::Horizontal;
334+
} else {
335+
unreachable!();
336+
}
337+
}
312338
DefinitiveListTactic::Vertical if !first => {
313339
result.push('\n');
314340
result.push_str(indent_str);

src/types.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,7 @@ impl Rewrite for ast::WherePredicate {
442442
{
443443
format!(
444444
"for< {} > {}{}{}",
445-
lifetime_str,
446-
type_str,
447-
colon,
448-
bounds_str
445+
lifetime_str, type_str, colon, bounds_str
449446
)
450447
} else {
451448
format!("for<{}> {}{}{}", lifetime_str, type_str, colon, bounds_str)

tests/source/macros.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,11 @@ make_test!(str_searcher_ascii_haystack, "bb", "abbcbbd", [
216216
Reject(6, 7),
217217
]);
218218
}
219+
220+
fn special_case_macros() {
221+
// format!
222+
let s = format!("Arr! While plunderin' the hold, we got '{}' when given '{}' (we expected '{}')", result, input, expected);
223+
224+
// assert!
225+
assert!(result, "Arr! While plunderin' the hold, we got '{}' when given '{}' (we expected '{}')", result, input, expected);
226+
}

0 commit comments

Comments
 (0)