Skip to content

Commit bb87a1b

Browse files
fee1-deadcalebcartwright
authored andcommitted
Rewrite float literals ending in dots with parens in method calls
1 parent 326af2b commit bb87a1b

File tree

4 files changed

+71
-24
lines changed

4 files changed

+71
-24
lines changed

src/chains.rs

+58-16
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,13 @@ enum CommentPosition {
153153
Top,
154154
}
155155

156-
// An expression plus trailing `?`s to be formatted together.
156+
/// Information about an expression in a chain.
157+
struct SubExpr {
158+
expr: ast::Expr,
159+
is_method_call_receiver: bool,
160+
}
161+
162+
/// An expression plus trailing `?`s to be formatted together.
157163
#[derive(Debug)]
158164
struct ChainItem {
159165
kind: ChainItemKind,
@@ -166,7 +172,10 @@ struct ChainItem {
166172
// would remove a lot of cloning.
167173
#[derive(Debug)]
168174
enum ChainItemKind {
169-
Parent(ast::Expr),
175+
Parent {
176+
expr: ast::Expr,
177+
parens: bool,
178+
},
170179
MethodCall(
171180
ast::PathSegment,
172181
Vec<ast::GenericArg>,
@@ -181,7 +190,7 @@ enum ChainItemKind {
181190
impl ChainItemKind {
182191
fn is_block_like(&self, context: &RewriteContext<'_>, reps: &str) -> bool {
183192
match self {
184-
ChainItemKind::Parent(ref expr) => utils::is_block_expr(context, expr, reps),
193+
ChainItemKind::Parent { expr, .. } => utils::is_block_expr(context, expr, reps),
185194
ChainItemKind::MethodCall(..)
186195
| ChainItemKind::StructField(..)
187196
| ChainItemKind::TupleField(..)
@@ -199,7 +208,11 @@ impl ChainItemKind {
199208
}
200209
}
201210

202-
fn from_ast(context: &RewriteContext<'_>, expr: &ast::Expr) -> (ChainItemKind, Span) {
211+
fn from_ast(
212+
context: &RewriteContext<'_>,
213+
expr: &ast::Expr,
214+
is_method_call_receiver: bool,
215+
) -> (ChainItemKind, Span) {
203216
let (kind, span) = match expr.kind {
204217
ast::ExprKind::MethodCall(ref call) => {
205218
let types = if let Some(ref generic_args) = call.seg.args {
@@ -236,7 +249,19 @@ impl ChainItemKind {
236249
let span = mk_sp(nested.span.hi(), expr.span.hi());
237250
(ChainItemKind::Await, span)
238251
}
239-
_ => return (ChainItemKind::Parent(expr.clone()), expr.span),
252+
_ => {
253+
return (
254+
ChainItemKind::Parent {
255+
expr: expr.clone(),
256+
parens: is_method_call_receiver
257+
&& matches!(
258+
&expr.kind,
259+
ast::ExprKind::Lit(lit) if crate::expr::lit_ends_in_dot(lit)
260+
),
261+
},
262+
expr.span,
263+
);
264+
}
240265
};
241266

242267
// Remove comments from the span.
@@ -249,7 +274,14 @@ impl Rewrite for ChainItem {
249274
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
250275
let shape = shape.sub_width(self.tries)?;
251276
let rewrite = match self.kind {
252-
ChainItemKind::Parent(ref expr) => expr.rewrite(context, shape)?,
277+
ChainItemKind::Parent {
278+
ref expr,
279+
parens: true,
280+
} => crate::expr::rewrite_paren(context, &expr, shape, expr.span)?,
281+
ChainItemKind::Parent {
282+
ref expr,
283+
parens: false,
284+
} => expr.rewrite(context, shape)?,
253285
ChainItemKind::MethodCall(ref segment, ref types, ref exprs) => {
254286
Self::rewrite_method_call(segment.ident, types, exprs, self.span, context, shape)?
255287
}
@@ -273,8 +305,9 @@ impl Rewrite for ChainItem {
273305
}
274306

275307
impl ChainItem {
276-
fn new(context: &RewriteContext<'_>, expr: &ast::Expr, tries: usize) -> ChainItem {
277-
let (kind, span) = ChainItemKind::from_ast(context, expr);
308+
fn new(context: &RewriteContext<'_>, expr: &SubExpr, tries: usize) -> ChainItem {
309+
let (kind, span) =
310+
ChainItemKind::from_ast(context, &expr.expr, expr.is_method_call_receiver);
278311
ChainItem { kind, tries, span }
279312
}
280313

@@ -327,7 +360,7 @@ impl Chain {
327360
let mut rev_children = vec![];
328361
let mut sub_tries = 0;
329362
for subexpr in &subexpr_list {
330-
match subexpr.kind {
363+
match subexpr.expr.kind {
331364
ast::ExprKind::Try(_) => sub_tries += 1,
332365
_ => {
333366
rev_children.push(ChainItem::new(context, subexpr, sub_tries));
@@ -442,24 +475,33 @@ impl Chain {
442475

443476
// Returns a Vec of the prefixes of the chain.
444477
// E.g., for input `a.b.c` we return [`a.b.c`, `a.b`, 'a']
445-
fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<ast::Expr> {
446-
let mut subexpr_list = vec![expr.clone()];
478+
fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<SubExpr> {
479+
let mut subexpr_list = vec![SubExpr {
480+
expr: expr.clone(),
481+
is_method_call_receiver: false,
482+
}];
447483

448484
while let Some(subexpr) = Self::pop_expr_chain(subexpr_list.last().unwrap(), context) {
449-
subexpr_list.push(subexpr.clone());
485+
subexpr_list.push(subexpr);
450486
}
451487

452488
subexpr_list
453489
}
454490

455491
// Returns the expression's subexpression, if it exists. When the subexpr
456492
// is a try! macro, we'll convert it to shorthand when the option is set.
457-
fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext<'_>) -> Option<ast::Expr> {
458-
match expr.kind {
459-
ast::ExprKind::MethodCall(ref call) => Some(Self::convert_try(&call.receiver, context)),
493+
fn pop_expr_chain(expr: &SubExpr, context: &RewriteContext<'_>) -> Option<SubExpr> {
494+
match expr.expr.kind {
495+
ast::ExprKind::MethodCall(ref call) => Some(SubExpr {
496+
expr: Self::convert_try(&call.receiver, context),
497+
is_method_call_receiver: true,
498+
}),
460499
ast::ExprKind::Field(ref subexpr, _)
461500
| ast::ExprKind::Try(ref subexpr)
462-
| ast::ExprKind::Await(ref subexpr, _) => Some(Self::convert_try(subexpr, context)),
501+
| ast::ExprKind::Await(ref subexpr, _) => Some(SubExpr {
502+
expr: Self::convert_try(subexpr, context),
503+
is_method_call_receiver: false,
504+
}),
463505
_ => None,
464506
}
465507
}

src/expr.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::borrow::Cow;
22
use std::cmp::min;
33

44
use itertools::Itertools;
5-
use rustc_ast::token::{Delimiter, LitKind};
5+
use rustc_ast::token::{Delimiter, Lit, LitKind};
66
use rustc_ast::{ast, ptr, token};
77
use rustc_span::{BytePos, Span};
88

@@ -48,6 +48,10 @@ pub(crate) enum ExprType {
4848
SubExpression,
4949
}
5050

51+
pub(crate) fn lit_ends_in_dot(lit: &Lit) -> bool {
52+
matches!(lit, Lit { kind: LitKind::Float, suffix: None, symbol } if symbol.as_str().ends_with('.'))
53+
}
54+
5155
pub(crate) fn format_expr(
5256
expr: &ast::Expr,
5357
expr_type: ExprType,
@@ -275,12 +279,7 @@ pub(crate) fn format_expr(
275279

276280
fn needs_space_before_range(context: &RewriteContext<'_>, lhs: &ast::Expr) -> bool {
277281
match lhs.kind {
278-
ast::ExprKind::Lit(token_lit) => match token_lit.kind {
279-
token::LitKind::Float if token_lit.suffix.is_none() => {
280-
context.snippet(lhs.span).ends_with('.')
281-
}
282-
_ => false,
283-
},
282+
ast::ExprKind::Lit(token_lit) => lit_ends_in_dot(&token_lit),
284283
ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr),
285284
_ => false,
286285
}
@@ -1440,7 +1439,7 @@ pub(crate) fn span_ends_with_comma(context: &RewriteContext<'_>, span: Span) ->
14401439
result
14411440
}
14421441

1443-
fn rewrite_paren(
1442+
pub(crate) fn rewrite_paren(
14441443
context: &RewriteContext<'_>,
14451444
mut subexpr: &ast::Expr,
14461445
shape: Shape,

tests/source/issue-5791.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub fn main() {
2+
0. .to_string();
3+
}

tests/target/issue-5791.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub fn main() {
2+
(0.).to_string();
3+
}

0 commit comments

Comments
 (0)