X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;ds=sidebyside;f=src%2Fchains.rs;h=e26e24ec55ad6c40fe495ddc41c57cba89e218c5;hb=ac595dd57a151a16a168e6596404ada8f079b778;hp=3acb8e2eac31b72bda951997a2e90af227e0508b;hpb=a67208f212657f94833792148e3e3e09fe0785ba;p=rust.git diff --git a/src/chains.rs b/src/chains.rs index 3acb8e2eac3..e26e24ec55a 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -1,15 +1,5 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Formatting of chained expressions, i.e. expressions which are chained by -//! dots: struct and enum field access, method calls, and try shorthand (?). +//! Formatting of chained expressions, i.e., expressions that are chained by +//! dots: struct and enum field access, method calls, and try shorthand (`?`). //! //! Instead of walking these subexpressions one-by-one, as is our usual strategy //! for expression formatting, we collect maximal sequences of these expressions @@ -26,7 +16,7 @@ //! following values of `chain_indent`: //! Block: //! -//! ```ignore +//! ```text //! let foo = { //! aaaa; //! bbb; @@ -37,7 +27,7 @@ //! //! Visual: //! -//! ```ignore +//! ```text //! let foo = { //! aaaa; //! bbb; @@ -51,7 +41,7 @@ //! the braces. //! Block: //! -//! ```ignore +//! ```text //! let a = foo.bar //! .baz() //! .qux @@ -59,33 +49,36 @@ //! //! Visual: //! -//! ```ignore +//! ```text //! let a = foo.bar //! .baz() //! .qux //! ``` -use comment::{rewrite_comment, CharClasses, FullCodeCharKind, RichChar}; -use config::IndentStyle; -use expr::rewrite_call; -use lists::extract_pre_comment; -use macros::convert_try_mac; -use rewrite::{Rewrite, RewriteContext}; -use shape::Shape; -use source_map::SpanUtils; -use utils::{ - first_line_width, last_line_extendable, last_line_width, mk_sp, rewrite_ident, - trimmed_last_line_width, wrap_str, -}; - use std::borrow::Cow; use std::cmp::min; -use std::iter; -use syntax::source_map::{BytePos, Span}; -use syntax::{ast, ptr}; +use rustc_ast::{ast, ptr}; +use rustc_span::{symbol, BytePos, Span}; + +use crate::comment::{rewrite_comment, CharClasses, FullCodeCharKind, RichChar}; +use crate::config::{IndentStyle, Version}; +use crate::expr::rewrite_call; +use crate::lists::extract_pre_comment; +use crate::macros::convert_try_mac; +use crate::rewrite::{Rewrite, RewriteContext}; +use crate::shape::Shape; +use crate::source_map::SpanUtils; +use crate::utils::{ + self, first_line_width, last_line_extendable, last_line_width, mk_sp, rewrite_ident, + trimmed_last_line_width, wrap_str, +}; -pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -> Option { +pub(crate) fn rewrite_chain( + expr: &ast::Expr, + context: &RewriteContext<'_>, + shape: Shape, +) -> Option { let chain = Chain::from_ast(expr, context); debug!("rewrite_chain {:?} {:?}", chain, shape); @@ -123,24 +116,26 @@ enum ChainItemKind { Vec, Vec>, ), - StructField(ast::Ident), - TupleField(ast::Ident, bool), + StructField(symbol::Ident), + TupleField(symbol::Ident, bool), + Await, Comment(String, CommentPosition), } impl ChainItemKind { - fn is_block_like(&self, context: &RewriteContext, reps: &str) -> bool { + fn is_block_like(&self, context: &RewriteContext<'_>, reps: &str) -> bool { match self { - ChainItemKind::Parent(ref expr) => is_block_expr(context, expr, reps), - ChainItemKind::MethodCall(..) => reps.contains('\n'), - ChainItemKind::StructField(..) + ChainItemKind::Parent(ref expr) => utils::is_block_expr(context, expr, reps), + ChainItemKind::MethodCall(..) + | ChainItemKind::StructField(..) | ChainItemKind::TupleField(..) + | ChainItemKind::Await | ChainItemKind::Comment(..) => false, } } fn is_tup_field_access(expr: &ast::Expr) -> bool { - match expr.node { + match expr.kind { ast::ExprKind::Field(_, ref field) => { field.name.to_string().chars().all(|c| c.is_digit(10)) } @@ -148,12 +143,20 @@ fn is_tup_field_access(expr: &ast::Expr) -> bool { } } - fn from_ast(context: &RewriteContext, expr: &ast::Expr) -> (ChainItemKind, Span) { - let (kind, span) = match expr.node { - ast::ExprKind::MethodCall(ref segment, ref expressions) => { + fn from_ast(context: &RewriteContext<'_>, expr: &ast::Expr) -> (ChainItemKind, Span) { + let (kind, span) = match expr.kind { + ast::ExprKind::MethodCall(ref segment, ref expressions, _) => { let types = if let Some(ref generic_args) = segment.args { if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args { - data.args.clone() + data.args + .iter() + .filter_map(|x| match x { + ast::AngleBracketedArg::Arg(ref generic_arg) => { + Some(generic_arg.clone()) + } + _ => None, + }) + .collect::>() } else { vec![] } @@ -173,6 +176,10 @@ fn from_ast(context: &RewriteContext, expr: &ast::Expr) -> (ChainItemKind, Span) let span = mk_sp(nested.span.hi(), field.span.hi()); (kind, span) } + ast::ExprKind::Await(ref nested) => { + let span = mk_sp(nested.span.hi(), expr.span.hi()); + (ChainItemKind::Await, span) + } _ => return (ChainItemKind::Parent(expr.clone()), expr.span), }; @@ -183,7 +190,7 @@ fn from_ast(context: &RewriteContext, expr: &ast::Expr) -> (ChainItemKind, Span) } impl Rewrite for ChainItem { - fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { let shape = shape.sub_width(self.tries)?; let rewrite = match self.kind { ChainItemKind::Parent(ref expr) => expr.rewrite(context, shape)?, @@ -193,9 +200,14 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { ChainItemKind::StructField(ident) => format!(".{}", rewrite_ident(context, ident)), ChainItemKind::TupleField(ident, nested) => format!( "{}.{}", - if nested { " " } else { "" }, + if nested && context.config.version() == Version::One { + " " + } else { + "" + }, rewrite_ident(context, ident) ), + ChainItemKind::Await => ".await".to_owned(), ChainItemKind::Comment(ref comment, _) => { rewrite_comment(comment, false, shape, context.config)? } @@ -205,7 +217,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { } impl ChainItem { - fn new(context: &RewriteContext, expr: &ast::Expr, tries: usize) -> ChainItem { + fn new(context: &RewriteContext<'_>, expr: &ast::Expr, tries: usize) -> ChainItem { let (kind, span) = ChainItemKind::from_ast(context, expr); ChainItem { kind, tries, span } } @@ -219,18 +231,15 @@ fn comment(span: Span, comment: String, pos: CommentPosition) -> ChainItem { } fn is_comment(&self) -> bool { - match self.kind { - ChainItemKind::Comment(..) => true, - _ => false, - } + matches!(self.kind, ChainItemKind::Comment(..)) } fn rewrite_method_call( - method_name: ast::Ident, + method_name: symbol::Ident, types: &[ast::GenericArg], args: &[ptr::P], span: Span, - context: &RewriteContext, + context: &RewriteContext<'_>, shape: Shape, ) -> Option { let type_str = if types.is_empty() { @@ -255,14 +264,14 @@ struct Chain { } impl Chain { - fn from_ast(expr: &ast::Expr, context: &RewriteContext) -> Chain { + fn from_ast(expr: &ast::Expr, context: &RewriteContext<'_>) -> Chain { let subexpr_list = Self::make_subexpr_list(expr, context); // Un-parse the expression tree into ChainItems let mut rev_children = vec![]; let mut sub_tries = 0; for subexpr in &subexpr_list { - match subexpr.node { + match subexpr.kind { ast::ExprKind::Try(_) => sub_tries += 1, _ => { rev_children.push(ChainItem::new(context, subexpr, sub_tries)); @@ -377,7 +386,7 @@ 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 { + fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec { let mut subexpr_list = vec![expr.clone()]; while let Some(subexpr) = Self::pop_expr_chain(subexpr_list.last().unwrap(), context) { @@ -389,21 +398,21 @@ fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext) -> Vec Option { - match expr.node { - ast::ExprKind::MethodCall(_, ref expressions) => { + fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext<'_>) -> Option { + match expr.kind { + ast::ExprKind::MethodCall(_, ref expressions, _) => { Some(Self::convert_try(&expressions[0], context)) } - ast::ExprKind::Field(ref subexpr, _) | ast::ExprKind::Try(ref subexpr) => { - Some(Self::convert_try(subexpr, context)) - } + ast::ExprKind::Field(ref subexpr, _) + | ast::ExprKind::Try(ref subexpr) + | ast::ExprKind::Await(ref subexpr) => Some(Self::convert_try(subexpr, context)), _ => None, } } - fn convert_try(expr: &ast::Expr, context: &RewriteContext) -> ast::Expr { - match expr.node { - ast::ExprKind::Mac(ref mac) if context.config.use_try_shorthand() => { + fn convert_try(expr: &ast::Expr, context: &RewriteContext<'_>) -> ast::Expr { + match expr.kind { + ast::ExprKind::MacCall(ref mac) if context.config.use_try_shorthand() => { if let Some(subexpr) = convert_try_mac(mac, context) { subexpr } else { @@ -416,12 +425,16 @@ fn convert_try(expr: &ast::Expr, context: &RewriteContext) -> ast::Expr { } impl Rewrite for Chain { - fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { debug!("rewrite chain {:?} {:?}", self, shape); let mut formatter = match context.config.indent_style() { - IndentStyle::Block => Box::new(ChainFormatterBlock::new(self)) as Box, - IndentStyle::Visual => Box::new(ChainFormatterVisual::new(self)) as Box, + IndentStyle::Block => { + Box::new(ChainFormatterBlock::new(self)) as Box + } + IndentStyle::Visual => { + Box::new(ChainFormatterVisual::new(self)) as Box + } }; formatter.format_root(&self.parent, context, shape)?; @@ -448,7 +461,7 @@ trait ChainFormatter { // Parent is the first item in the chain, e.g., `foo` in `foo.bar.baz()`. // Root is the parent plus any other chain items placed on the first line to // avoid an orphan. E.g., - // ``` + // ```text // foo.bar // .baz() // ``` @@ -456,18 +469,18 @@ trait ChainFormatter { fn format_root( &mut self, parent: &ChainItem, - context: &RewriteContext, + context: &RewriteContext<'_>, shape: Shape, ) -> Option<()>; - fn child_shape(&self, context: &RewriteContext, shape: Shape) -> Option; - fn format_children(&mut self, context: &RewriteContext, child_shape: Shape) -> Option<()>; + fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option; + fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()>; fn format_last_child( &mut self, - context: &RewriteContext, + context: &RewriteContext<'_>, shape: Shape, child_shape: Shape, ) -> Option<()>; - fn join_rewrites(&self, context: &RewriteContext, child_shape: Shape) -> Option; + fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> Option; // Returns `Some` if the chain is only a root, None otherwise. fn pure_root(&mut self) -> Option; } @@ -510,7 +523,7 @@ fn pure_root(&mut self) -> Option { // know whether 'overflowing' the last child make a better formatting: // // A chain with overflowing the last child: - // ``` + // ```text // parent.child1.child2.last_child( // a, // b, @@ -519,7 +532,7 @@ fn pure_root(&mut self) -> Option { // ``` // // A chain without overflowing the last child (in vertical layout): - // ``` + // ```text // parent // .child1 // .child2 @@ -527,8 +540,8 @@ fn pure_root(&mut self) -> Option { // ``` // // In particular, overflowing is effective when the last child is a method with a multi-lined - // block-like argument (e.g. closure): - // ``` + // block-like argument (e.g., closure): + // ```text // parent.child1.child2.last_child(|a, b, c| { // let x = foo(a, b, c); // let y = bar(a, b, c); @@ -541,7 +554,7 @@ fn pure_root(&mut self) -> Option { fn format_last_child( &mut self, may_extend: bool, - context: &RewriteContext, + context: &RewriteContext<'_>, shape: Shape, child_shape: Shape, ) -> Option<()> { @@ -553,13 +566,17 @@ fn format_last_child( let almost_total = if extendable { prev_last_line_width } else { - self.rewrites.iter().fold(0, |a, b| a + b.len()) + self.rewrites + .iter() + .map(|rw| utils::unicode_str_width(rw)) + .sum() } + last.tries; let one_line_budget = if self.child_count == 1 { shape.width } else { - min(shape.width, context.config.width_heuristics().chain_width) - }.saturating_sub(almost_total); + min(shape.width, context.config.chain_width()) + } + .saturating_sub(almost_total); let all_in_one_line = !self.children.iter().any(ChainItem::is_comment) && self.rewrites.iter().all(|s| !s.contains('\n')) @@ -576,7 +593,15 @@ fn format_last_child( if all_in_one_line || extendable { // First we try to 'overflow' the last child and see if it looks better than using // vertical layout. - if let Some(one_line_shape) = last_shape.offset_left(almost_total) { + let one_line_shape = if context.use_block_indent() { + last_shape.offset_left(almost_total) + } else { + last_shape + .visual_indent(almost_total) + .sub_width(almost_total) + }; + + if let Some(one_line_shape) = one_line_shape { if let Some(rw) = last.rewrite(context, one_line_shape) { // We allow overflowing here only if both of the following conditions match: // 1. The entire chain fits in a single line except the last child. @@ -614,23 +639,24 @@ fn format_last_child( } } + let last_shape = if context.use_block_indent() { + last_shape + } else { + child_shape.sub_width(shape.rhs_overhead(context.config) + last.tries)? + }; + last_subexpr_str = last_subexpr_str.or_else(|| last.rewrite(context, last_shape)); self.rewrites.push(last_subexpr_str?); Some(()) } - fn join_rewrites( - &self, - context: &RewriteContext, - child_shape: Shape, - block_like_iter: impl Iterator, - ) -> Option { + fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> Option { let connector = if self.fits_single_line { // Yay, we can put everything on one line. Cow::from("") } else { // Use new lines. - if *context.force_one_line_chain.borrow() { + if context.force_one_line_chain.get() { return None; } child_shape.to_string_with_newline(context.config) @@ -639,19 +665,15 @@ fn join_rewrites( let mut rewrite_iter = self.rewrites.iter(); let mut result = rewrite_iter.next().unwrap().clone(); let children_iter = self.children.iter(); - let iter = rewrite_iter.zip(block_like_iter).zip(children_iter); + let iter = rewrite_iter.zip(children_iter); - for ((rewrite, prev_is_block_like), chain_item) in iter { + for (rewrite, chain_item) in iter { match chain_item.kind { ChainItemKind::Comment(_, CommentPosition::Back) => result.push(' '), ChainItemKind::Comment(_, CommentPosition::Top) => result.push_str(&connector), - _ => { - if !prev_is_block_like { - result.push_str(&connector); - } - } + _ => result.push_str(&connector), } - result.push_str(&rewrite); + result.push_str(rewrite); } Some(result) @@ -661,15 +683,14 @@ fn join_rewrites( // Formats a chain using block indent. struct ChainFormatterBlock<'a> { shared: ChainFormatterShared<'a>, - // For each rewrite, whether the corresponding item is block-like. - is_block_like: Vec, + root_ends_with_block: bool, } impl<'a> ChainFormatterBlock<'a> { fn new(chain: &'a Chain) -> ChainFormatterBlock<'a> { ChainFormatterBlock { shared: ChainFormatterShared::new(chain), - is_block_like: Vec::with_capacity(chain.children.len() + 1), + root_ends_with_block: false, } } } @@ -678,7 +699,7 @@ impl<'a> ChainFormatter for ChainFormatterBlock<'a> { fn format_root( &mut self, parent: &ChainItem, - context: &RewriteContext, + context: &RewriteContext<'_>, shape: Shape, ) -> Option<()> { let mut root_rewrite: String = parent.rewrite(context, shape)?; @@ -697,33 +718,32 @@ fn format_root( None => break, } - root_ends_with_block = item.kind.is_block_like(context, &root_rewrite); + root_ends_with_block = last_line_extendable(&root_rewrite); self.shared.children = &self.shared.children[1..]; if self.shared.children.is_empty() { break; } } - self.is_block_like.push(root_ends_with_block); self.shared.rewrites.push(root_rewrite); + self.root_ends_with_block = root_ends_with_block; Some(()) } - fn child_shape(&self, context: &RewriteContext, shape: Shape) -> Option { + fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { Some( - if self.is_block_like[0] { + if self.root_ends_with_block { shape.block_indent(0) } else { shape.block_indent(context.config.tab_spaces()) - }.with_max_width(context.config), + } + .with_max_width(context.config), ) } - fn format_children(&mut self, context: &RewriteContext, child_shape: Shape) -> Option<()> { + fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> { for item in &self.shared.children[..self.shared.children.len() - 1] { let rewrite = item.rewrite(context, child_shape)?; - self.is_block_like - .push(item.kind.is_block_like(context, &rewrite)); self.shared.rewrites.push(rewrite); } Some(()) @@ -731,7 +751,7 @@ fn format_children(&mut self, context: &RewriteContext, child_shape: Shape) -> O fn format_last_child( &mut self, - context: &RewriteContext, + context: &RewriteContext<'_>, shape: Shape, child_shape: Shape, ) -> Option<()> { @@ -739,9 +759,8 @@ fn format_last_child( .format_last_child(true, context, shape, child_shape) } - fn join_rewrites(&self, context: &RewriteContext, child_shape: Shape) -> Option { - self.shared - .join_rewrites(context, child_shape, self.is_block_like.iter().cloned()) + fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> Option { + self.shared.join_rewrites(context, child_shape) } fn pure_root(&mut self) -> Option { @@ -769,7 +788,7 @@ impl<'a> ChainFormatter for ChainFormatterVisual<'a> { fn format_root( &mut self, parent: &ChainItem, - context: &RewriteContext, + context: &RewriteContext<'_>, shape: Shape, ) -> Option<()> { let parent_shape = shape.visual_indent(0); @@ -809,14 +828,14 @@ fn format_root( Some(()) } - fn child_shape(&self, context: &RewriteContext, shape: Shape) -> Option { + fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { shape .with_max_width(context.config) .offset_left(self.offset) .map(|s| s.visual_indent(0)) } - fn format_children(&mut self, context: &RewriteContext, child_shape: Shape) -> Option<()> { + fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> { for item in &self.shared.children[..self.shared.children.len() - 1] { let rewrite = item.rewrite(context, child_shape)?; self.shared.rewrites.push(rewrite); @@ -826,7 +845,7 @@ fn format_children(&mut self, context: &RewriteContext, child_shape: Shape) -> O fn format_last_child( &mut self, - context: &RewriteContext, + context: &RewriteContext<'_>, shape: Shape, child_shape: Shape, ) -> Option<()> { @@ -834,9 +853,8 @@ fn format_last_child( .format_last_child(false, context, shape, child_shape) } - fn join_rewrites(&self, context: &RewriteContext, child_shape: Shape) -> Option { - self.shared - .join_rewrites(context, child_shape, iter::repeat(false)) + fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> Option { + self.shared.join_rewrites(context, child_shape) } fn pure_root(&mut self) -> Option { @@ -844,38 +862,7 @@ fn pure_root(&mut self) -> Option { } } -// States whether an expression's last line exclusively consists of closing -// parens, braces, and brackets in its idiomatic formatting. -fn is_block_expr(context: &RewriteContext, expr: &ast::Expr, repr: &str) -> bool { - match expr.node { - ast::ExprKind::Mac(..) - | ast::ExprKind::Call(..) - | ast::ExprKind::MethodCall(..) - | ast::ExprKind::Struct(..) - | ast::ExprKind::While(..) - | ast::ExprKind::WhileLet(..) - | ast::ExprKind::If(..) - | ast::ExprKind::IfLet(..) - | ast::ExprKind::Block(..) - | ast::ExprKind::Loop(..) - | ast::ExprKind::ForLoop(..) - | ast::ExprKind::Match(..) => repr.contains('\n'), - ast::ExprKind::Paren(ref expr) - | ast::ExprKind::Binary(_, _, ref expr) - | ast::ExprKind::Index(_, ref expr) - | ast::ExprKind::Unary(_, ref expr) - | ast::ExprKind::Closure(_, _, _, _, ref expr, _) - | ast::ExprKind::Try(ref expr) - | ast::ExprKind::Yield(Some(ref expr)) => is_block_expr(context, expr, repr), - // This can only be a string lit - ast::ExprKind::Lit(_) => { - repr.contains('\n') && trimmed_last_line_width(repr) <= context.config.tab_spaces() - } - _ => false, - } -} - -/// Remove try operators (`?`s) that appear in the given string. If removing +/// Removes try operators (`?`s) that appear in the given string. If removing /// them leaves an empty line, remove that line as well unless it is the first /// line (we need the first newline for detecting pre/post comment). fn trim_tries(s: &str) -> String {