Skip to content

Commit cd158ce

Browse files
committed
Add try macro to try shorthand conversion tests
1 parent ee7b580 commit cd158ce

File tree

8 files changed

+134
-49
lines changed

8 files changed

+134
-49
lines changed

src/chains.rs

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -86,18 +86,18 @@ use rewrite::{Rewrite, RewriteContext};
8686
use utils::{wrap_str, first_line_width};
8787
use expr::rewrite_call;
8888
use config::BlockIndentStyle;
89+
use macros::convert_try_mac;
8990

9091
use syntax::{ast, ptr};
9192
use syntax::codemap::{mk_sp, Span};
9293

93-
9494
pub fn rewrite_chain(expr: &ast::Expr,
9595
context: &RewriteContext,
9696
width: usize,
9797
offset: Indent)
9898
-> Option<String> {
9999
let total_span = expr.span;
100-
let (parent, subexpr_list) = make_subexpr_list(expr);
100+
let (parent, subexpr_list) = make_subexpr_list(expr, context);
101101

102102
// Parent is the first item in the chain, e.g., `foo` in `foo.bar.baz()`.
103103
let parent_block_indent = chain_base_indent(context, offset);
@@ -106,19 +106,16 @@ pub fn rewrite_chain(expr: &ast::Expr,
106106

107107
// Decide how to layout the rest of the chain. `extend` is true if we can
108108
// put the first non-parent item on the same line as the parent.
109-
let (indent, extend) = if !parent_rewrite.contains('\n') && is_continuable(parent) ||
109+
let (indent, extend) = if !parent_rewrite.contains('\n') && is_continuable(&parent) ||
110110
parent_rewrite.len() <= context.config.tab_spaces {
111-
// <<<<<<< HEAD
112-
// // Try and put at least the first two items on the same line.
113-
// (chain_indent(context, offset + Indent::new(0, parent_rewrite.len())), true)
114-
// =======
111+
115112
let indent = if let ast::ExprKind::Try(..) = subexpr_list.last().unwrap().node {
116113
parent_block_indent.block_indent(context.config)
117114
} else {
118-
offset + Indent::new(0, parent_rewrite.len())
115+
chain_indent(context, offset + Indent::new(0, parent_rewrite.len()))
119116
};
120117
(indent, true)
121-
} else if is_block_expr(parent, &parent_rewrite) {
118+
} else if is_block_expr(&parent, &parent_rewrite) {
122119
// The parent is a block, so align the rest of the chain with the closing
123120
// brace.
124121
(parent_block_indent, false)
@@ -197,11 +194,13 @@ pub fn rewrite_chain(expr: &ast::Expr,
197194
offset)
198195
}
199196

200-
fn join_rewrites(rewrites: &[String], subexps: &[&ast::Expr], connector: &str) -> String {
197+
fn join_rewrites(rewrites: &[String], subexps: &[ast::Expr], connector: &str) -> String {
201198
let mut rewrite_iter = rewrites.iter();
202199
let mut result = rewrite_iter.next().unwrap().clone();
200+
let mut subexpr_iter = subexps.iter().rev();
201+
subexpr_iter.next();
203202

204-
for (rewrite, expr) in rewrite_iter.zip(subexps.iter()) {
203+
for (rewrite, expr) in rewrite_iter.zip(subexpr_iter) {
205204
match expr.node {
206205
ast::ExprKind::Try(_) => (),
207206
_ => result.push_str(connector),
@@ -235,21 +234,11 @@ fn is_block_expr(expr: &ast::Expr, repr: &str) -> bool {
235234

236235
// Returns the root of the chain and a Vec of the prefixes of the rest of the chain.
237236
// E.g., for input `a.b.c` we return (`a`, [`a.b.c`, `a.b`])
238-
fn make_subexpr_list(mut expr: &ast::Expr) -> (&ast::Expr, Vec<&ast::Expr>) {
239-
fn pop_expr_chain(expr: &ast::Expr) -> Option<&ast::Expr> {
240-
match expr.node {
241-
ast::ExprKind::MethodCall(_, _, ref expressions) => Some(&expressions[0]),
242-
ast::ExprKind::TupField(ref subexpr, _) |
243-
ast::ExprKind::Field(ref subexpr, _) => Some(subexpr),
244-
_ => None,
245-
}
246-
}
247-
248-
let mut subexpr_list = vec![expr];
237+
fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext) -> (ast::Expr, Vec<ast::Expr>) {
238+
let mut subexpr_list = vec![expr.clone()];
249239

250-
while let Some(subexpr) = pop_expr_chain(expr) {
251-
subexpr_list.push(subexpr);
252-
expr = subexpr;
240+
while let Some(subexpr) = pop_expr_chain(subexpr_list.last().unwrap(), context) {
241+
subexpr_list.push(subexpr.clone());
253242
}
254243

255244
let parent = subexpr_list.pop().unwrap();
@@ -315,16 +304,33 @@ fn rewrite_method_call_with_overflow(expr_kind: &ast::ExprKind,
315304
}
316305
}
317306

318-
fn pop_expr_chain(expr: &ast::Expr) -> Option<&ast::Expr> {
307+
// Returns the expression's subexpression, if it exists. When the subexpr
308+
// is a try! macro, we'll convert it to shorthand when the option is set.
309+
fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext) -> Option<ast::Expr> {
319310
match expr.node {
320-
ast::ExprKind::MethodCall(_, _, ref expressions) => Some(&expressions[0]),
311+
ast::ExprKind::MethodCall(_, _, ref expressions) => {
312+
Some(convert_try(&expressions[0], context))
313+
}
321314
ast::ExprKind::TupField(ref subexpr, _) |
322315
ast::ExprKind::Field(ref subexpr, _) |
323-
ast::ExprKind::Try(ref subexpr) => Some(subexpr),
316+
ast::ExprKind::Try(ref subexpr) => Some(convert_try(subexpr, context)),
324317
_ => None,
325318
}
326319
}
327320

321+
fn convert_try(expr: &ast::Expr, context: &RewriteContext) -> ast::Expr {
322+
match expr.node {
323+
ast::ExprKind::Mac(ref mac) if context.config.use_try_shorthand => {
324+
if let Some(subexpr) = convert_try_mac(mac, context) {
325+
subexpr
326+
} else {
327+
expr.clone()
328+
}
329+
}
330+
_ => expr.clone(),
331+
}
332+
}
333+
328334
// Rewrite the last element in the chain `expr`. E.g., given `a.b.c` we rewrite
329335
// `.c`.
330336
fn rewrite_chain_subexpr(expr: &ast::Expr,

src/config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ create_config! {
392392
match_wildcard_trailing_comma: bool, true, "Put a trailing comma after a wildcard arm";
393393
closure_block_indent_threshold: isize, 5, "How many lines a closure must have before it is \
394394
block indented. -1 means never use block indent.";
395+
use_try_shorthand: bool, false, "Replace uses of the try! macro by the ? shorthand";
395396
write_mode: WriteMode, WriteMode::Replace,
396397
"What Write Mode to use when none is supplied: Replace, Overwrite, Display, Diff, Coverage";
397398
}

src/expr.rs

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ impl Rewrite for ast::Expr {
148148
ast::ExprKind::Closure(capture, ref fn_decl, ref body, _) => {
149149
rewrite_closure(capture, fn_decl, body, self.span, context, width, offset)
150150
}
151-
// ast::ExprKind::Try(..) |
151+
ast::ExprKind::Try(..) |
152152
ast::ExprKind::Field(..) |
153153
ast::ExprKind::TupField(..) |
154154
ast::ExprKind::MethodCall(..) => rewrite_chain(self, context, width, offset),
@@ -205,15 +205,10 @@ impl Rewrite for ast::Expr {
205205
(None, None) => wrap_str(delim.into(), context.config.max_width, width, offset),
206206
}
207207
}
208-
ast::ExprKind::Try(ref expr) => {
209-
rewrite_unary_suffix(context, "?", &**expr, width, offset)
210-
}
211208
// We do not format these expressions yet, but they should still
212209
// satisfy our width restrictions.
213210
ast::ExprKind::InPlace(..) |
214-
ast::ExprKind::InlineAsm(..) |
215-
// TODO(#848): Handle type ascription
216-
ast::ExprKind::Type(_, _) => {
211+
ast::ExprKind::InlineAsm(..) => {
217212
wrap_str(context.snippet(self.span),
218213
context.config.max_width,
219214
width,
@@ -1832,24 +1827,41 @@ pub fn rewrite_assign_rhs<S: Into<String>>(context: &RewriteContext,
18321827
let max_width = try_opt!(width.checked_sub(last_line_width + 1));
18331828
let rhs = ex.rewrite(&context, max_width, offset + last_line_width + 1);
18341829

1830+
fn count_line_breaks(src: &str) -> usize {
1831+
src.chars().filter(|&x| x == '\n').count()
1832+
}
1833+
18351834
match rhs {
1836-
Some(new_str) => {
1835+
Some(ref new_str) if count_line_breaks(new_str) < 2 => {
18371836
result.push(' ');
1838-
result.push_str(&new_str)
1837+
result.push_str(new_str);
18391838
}
1840-
None => {
1841-
// Expression did not fit on the same line as the identifier. Retry
1842-
// on the next line.
1839+
_ => {
1840+
// Expression did not fit on the same line as the identifier or is
1841+
// at least three lines big. Try splitting the line and see
1842+
// if that works better.
18431843
let new_offset = offset.block_indent(context.config);
1844-
result.push_str(&format!("\n{}", new_offset.to_string(context.config)));
1845-
1846-
// FIXME: we probably should related max_width to width instead of
1847-
// config.max_width where is the 1 coming from anyway?
1848-
let max_width = try_opt!(context.config.max_width.checked_sub(new_offset.width() + 1));
1844+
let max_width = try_opt!((width + offset.width()).checked_sub(new_offset.width()));
18491845
let inner_context = context.nested_context();
1850-
let rhs = ex.rewrite(&inner_context, max_width, new_offset);
1851-
1852-
result.push_str(&&try_opt!(rhs));
1846+
let new_rhs = ex.rewrite(&inner_context, max_width, new_offset);
1847+
1848+
// FIXME: DRY!
1849+
match (rhs, new_rhs) {
1850+
(Some(ref orig_rhs), Some(ref replacement_rhs))
1851+
if count_line_breaks(orig_rhs) > count_line_breaks(replacement_rhs) + 1 => {
1852+
result.push_str(&format!("\n{}", new_offset.to_string(context.config)));
1853+
result.push_str(replacement_rhs);
1854+
}
1855+
(None, Some(ref final_rhs)) => {
1856+
result.push_str(&format!("\n{}", new_offset.to_string(context.config)));
1857+
result.push_str(final_rhs);
1858+
}
1859+
(None, None) => return None,
1860+
(Some(ref orig_rhs), _) => {
1861+
result.push(' ');
1862+
result.push_str(orig_rhs);
1863+
}
1864+
}
18531865
}
18541866
}
18551867

src/macros.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use syntax::parse::tts_to_parser;
2525
use syntax::codemap::{mk_sp, BytePos};
2626

2727
use Indent;
28-
use rewrite::RewriteContext;
28+
use rewrite::{Rewrite, RewriteContext};
2929
use expr::{rewrite_call, rewrite_array};
3030
use comment::{FindUncommented, contains_comment};
3131
use utils::{CodeMapSpanUtils, wrap_str};
@@ -56,6 +56,12 @@ pub fn rewrite_macro(mac: &ast::Mac,
5656
width: usize,
5757
offset: Indent)
5858
-> Option<String> {
59+
if context.config.use_try_shorthand {
60+
if let Some(expr) = convert_try_mac(mac, context) {
61+
return expr.rewrite(context, width, offset);
62+
}
63+
}
64+
5965
let original_style = macro_style(mac, context);
6066
let macro_name = match extra_ident {
6167
None |
@@ -141,6 +147,24 @@ pub fn rewrite_macro(mac: &ast::Mac,
141147
}
142148
}
143149

150+
/// Tries to convert a macro use into a short hand try expression. Returns None
151+
/// when the macro is not an instance of try! (or parsing the inner expression
152+
/// failed).
153+
pub fn convert_try_mac(mac: &ast::Mac, context: &RewriteContext) -> Option<ast::Expr> {
154+
if &format!("{}", mac.node.path)[..] == "try" {
155+
let mut parser = tts_to_parser(context.parse_session, mac.node.tts.clone(), Vec::new());
156+
157+
Some(ast::Expr {
158+
id: 0, // dummy value
159+
node: ast::ExprKind::Try(try_opt!(parser.parse_expr().ok())),
160+
span: mac.span, // incorrect span, but shouldn't matter too much
161+
attrs: None,
162+
})
163+
} else {
164+
None
165+
}
166+
}
167+
144168
fn macro_style(mac: &ast::Mac, context: &RewriteContext) -> MacroStyle {
145169
let snippet = context.snippet(mac.span);
146170
let paren_pos = snippet.find_uncommented("(").unwrap_or(usize::max_value());

tests/source/chains.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,8 @@ fn try_shorthand() {
120120
let yyyy = expr?.another?.another?.another?.another?.another?.another?.another?.another?.test();
121121
let zzzz = expr?.another?.another?.another?.another?;
122122
let aaa = x ???????????? ?????????????? ???? ????? ?????????????? ????????? ?????????????? ??;
123+
124+
let y = a.very .loooooooooooooooooooooooooooooooooooooong() .chain()
125+
.inside() .weeeeeeeeeeeeeee()? .test() .0
126+
.x;
123127
}

tests/source/try-conversion.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// rustfmt-use_try_shorthand: true
2+
3+
fn main() {
4+
let x = try!(some_expr());
5+
6+
let y = try!(a.very.loooooooooooooooooooooooooooooooooooooong().chain().inside().weeeeeeeeeeeeeee()).test().0.x;
7+
}
8+
9+
fn test() {
10+
a?
11+
}

tests/target/chains.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,13 @@ fn try_shorthand() {
145145
let yyyy = expr?.another?.another?.another?.another?.another?.another?.another?.another?.test();
146146
let zzzz = expr?.another?.another?.another?.another?;
147147
let aaa = x??????????????????????????????????????????????????????????????????????????;
148+
149+
let y = a.very
150+
.loooooooooooooooooooooooooooooooooooooong()
151+
.chain()
152+
.inside()
153+
.weeeeeeeeeeeeeee()?
154+
.test()
155+
.0
156+
.x;
148157
}

tests/target/try-conversion.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// rustfmt-use_try_shorthand: true
2+
3+
fn main() {
4+
let x = some_expr()?;
5+
6+
let y = a.very
7+
.loooooooooooooooooooooooooooooooooooooong()
8+
.chain()
9+
.inside()
10+
.weeeeeeeeeeeeeee()?
11+
.test()
12+
.0
13+
.x;
14+
}
15+
16+
fn test() {
17+
a?
18+
}

0 commit comments

Comments
 (0)