Rewrite float literals ending in dots with parens in method calls

This commit is contained in:
Deadbeef 2023-06-21 14:11:26 +00:00 committed by Caleb Cartwright
parent 326af2bd21
commit bb87a1b717
4 changed files with 71 additions and 24 deletions

View File

@ -153,7 +153,13 @@ enum CommentPosition {
Top,
}
// An expression plus trailing `?`s to be formatted together.
/// Information about an expression in a chain.
struct SubExpr {
expr: ast::Expr,
is_method_call_receiver: bool,
}
/// An expression plus trailing `?`s to be formatted together.
#[derive(Debug)]
struct ChainItem {
kind: ChainItemKind,
@ -166,7 +172,10 @@ struct ChainItem {
// would remove a lot of cloning.
#[derive(Debug)]
enum ChainItemKind {
Parent(ast::Expr),
Parent {
expr: ast::Expr,
parens: bool,
},
MethodCall(
ast::PathSegment,
Vec<ast::GenericArg>,
@ -181,7 +190,7 @@ enum ChainItemKind {
impl ChainItemKind {
fn is_block_like(&self, context: &RewriteContext<'_>, reps: &str) -> bool {
match self {
ChainItemKind::Parent(ref expr) => utils::is_block_expr(context, expr, reps),
ChainItemKind::Parent { expr, .. } => utils::is_block_expr(context, expr, reps),
ChainItemKind::MethodCall(..)
| ChainItemKind::StructField(..)
| ChainItemKind::TupleField(..)
@ -199,7 +208,11 @@ fn is_tup_field_access(expr: &ast::Expr) -> bool {
}
}
fn from_ast(context: &RewriteContext<'_>, expr: &ast::Expr) -> (ChainItemKind, Span) {
fn from_ast(
context: &RewriteContext<'_>,
expr: &ast::Expr,
is_method_call_receiver: bool,
) -> (ChainItemKind, Span) {
let (kind, span) = match expr.kind {
ast::ExprKind::MethodCall(ref call) => {
let types = if let Some(ref generic_args) = call.seg.args {
@ -236,7 +249,19 @@ fn from_ast(context: &RewriteContext<'_>, expr: &ast::Expr) -> (ChainItemKind, S
let span = mk_sp(nested.span.hi(), expr.span.hi());
(ChainItemKind::Await, span)
}
_ => return (ChainItemKind::Parent(expr.clone()), expr.span),
_ => {
return (
ChainItemKind::Parent {
expr: expr.clone(),
parens: is_method_call_receiver
&& matches!(
&expr.kind,
ast::ExprKind::Lit(lit) if crate::expr::lit_ends_in_dot(lit)
),
},
expr.span,
);
}
};
// Remove comments from the span.
@ -249,7 +274,14 @@ impl Rewrite for ChainItem {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
let shape = shape.sub_width(self.tries)?;
let rewrite = match self.kind {
ChainItemKind::Parent(ref expr) => expr.rewrite(context, shape)?,
ChainItemKind::Parent {
ref expr,
parens: true,
} => crate::expr::rewrite_paren(context, &expr, shape, expr.span)?,
ChainItemKind::Parent {
ref expr,
parens: false,
} => expr.rewrite(context, shape)?,
ChainItemKind::MethodCall(ref segment, ref types, ref exprs) => {
Self::rewrite_method_call(segment.ident, types, exprs, self.span, context, shape)?
}
@ -273,8 +305,9 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
}
impl ChainItem {
fn new(context: &RewriteContext<'_>, expr: &ast::Expr, tries: usize) -> ChainItem {
let (kind, span) = ChainItemKind::from_ast(context, expr);
fn new(context: &RewriteContext<'_>, expr: &SubExpr, tries: usize) -> ChainItem {
let (kind, span) =
ChainItemKind::from_ast(context, &expr.expr, expr.is_method_call_receiver);
ChainItem { kind, tries, span }
}
@ -327,7 +360,7 @@ fn from_ast(expr: &ast::Expr, context: &RewriteContext<'_>) -> Chain {
let mut rev_children = vec![];
let mut sub_tries = 0;
for subexpr in &subexpr_list {
match subexpr.kind {
match subexpr.expr.kind {
ast::ExprKind::Try(_) => sub_tries += 1,
_ => {
rev_children.push(ChainItem::new(context, subexpr, sub_tries));
@ -442,11 +475,14 @@ fn handle_post_comment(
// Returns a Vec of the prefixes of the chain.
// E.g., for input `a.b.c` we return [`a.b.c`, `a.b`, 'a']
fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<ast::Expr> {
let mut subexpr_list = vec![expr.clone()];
fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<SubExpr> {
let mut subexpr_list = vec![SubExpr {
expr: expr.clone(),
is_method_call_receiver: false,
}];
while let Some(subexpr) = Self::pop_expr_chain(subexpr_list.last().unwrap(), context) {
subexpr_list.push(subexpr.clone());
subexpr_list.push(subexpr);
}
subexpr_list
@ -454,12 +490,18 @@ fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<ast:
// Returns the expression's subexpression, if it exists. When the subexpr
// is a try! macro, we'll convert it to shorthand when the option is set.
fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext<'_>) -> Option<ast::Expr> {
match expr.kind {
ast::ExprKind::MethodCall(ref call) => Some(Self::convert_try(&call.receiver, context)),
fn pop_expr_chain(expr: &SubExpr, context: &RewriteContext<'_>) -> Option<SubExpr> {
match expr.expr.kind {
ast::ExprKind::MethodCall(ref call) => Some(SubExpr {
expr: Self::convert_try(&call.receiver, context),
is_method_call_receiver: true,
}),
ast::ExprKind::Field(ref subexpr, _)
| ast::ExprKind::Try(ref subexpr)
| ast::ExprKind::Await(ref subexpr, _) => Some(Self::convert_try(subexpr, context)),
| ast::ExprKind::Await(ref subexpr, _) => Some(SubExpr {
expr: Self::convert_try(subexpr, context),
is_method_call_receiver: false,
}),
_ => None,
}
}

View File

@ -2,7 +2,7 @@
use std::cmp::min;
use itertools::Itertools;
use rustc_ast::token::{Delimiter, LitKind};
use rustc_ast::token::{Delimiter, Lit, LitKind};
use rustc_ast::{ast, ptr, token};
use rustc_span::{BytePos, Span};
@ -48,6 +48,10 @@ pub(crate) enum ExprType {
SubExpression,
}
pub(crate) fn lit_ends_in_dot(lit: &Lit) -> bool {
matches!(lit, Lit { kind: LitKind::Float, suffix: None, symbol } if symbol.as_str().ends_with('.'))
}
pub(crate) fn format_expr(
expr: &ast::Expr,
expr_type: ExprType,
@ -275,12 +279,7 @@ pub(crate) fn format_expr(
fn needs_space_before_range(context: &RewriteContext<'_>, lhs: &ast::Expr) -> bool {
match lhs.kind {
ast::ExprKind::Lit(token_lit) => match token_lit.kind {
token::LitKind::Float if token_lit.suffix.is_none() => {
context.snippet(lhs.span).ends_with('.')
}
_ => false,
},
ast::ExprKind::Lit(token_lit) => lit_ends_in_dot(&token_lit),
ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr),
_ => false,
}
@ -1440,7 +1439,7 @@ pub(crate) fn span_ends_with_comma(context: &RewriteContext<'_>, span: Span) ->
result
}
fn rewrite_paren(
pub(crate) fn rewrite_paren(
context: &RewriteContext<'_>,
mut subexpr: &ast::Expr,
shape: Shape,

View File

@ -0,0 +1,3 @@
pub fn main() {
0. .to_string();
}

View File

@ -0,0 +1,3 @@
pub fn main() {
(0.).to_string();
}