1use std::borrow::Cow;
2use std::cmp::min;
3
4use itertools::Itertools;
5use rustc_ast::token::{Delimiter, Lit, LitKind};
6use rustc_ast::{ForLoopKind, MatchKind, ast, ptr, token};
7use rustc_span::{BytePos, Span};
8use tracing::debug;
9
10use crate::chains::rewrite_chain;
11use crate::closures;
12use crate::comment::{
13 CharClasses, FindUncommented, combine_strs_with_missing_comments, contains_comment,
14 recover_comment_removed, rewrite_comment, rewrite_missing_comment,
15};
16use crate::config::lists::*;
17use crate::config::{Config, ControlBraceStyle, HexLiteralCase, IndentStyle, StyleEdition};
18use crate::lists::{
19 ListFormatting, Separator, definitive_tactic, itemize_list, shape_for_tactic,
20 struct_lit_formatting, struct_lit_shape, struct_lit_tactic, write_list,
21};
22use crate::macros::{MacroPosition, rewrite_macro};
23use crate::matches::rewrite_match;
24use crate::overflow::{self, IntoOverflowableItem, OverflowableItem};
25use crate::pairs::{PairParts, rewrite_all_pairs, rewrite_pair};
26use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult};
27use crate::shape::{Indent, Shape};
28use crate::source_map::{LineRangeUtils, SpanUtils};
29use crate::spanned::Spanned;
30use crate::stmt;
31use crate::string::{StringFormat, rewrite_string};
32use crate::types::{PathContext, rewrite_path};
33use crate::utils::{
34 colon_spaces, contains_skip, count_newlines, filtered_str_fits, first_line_ends_with,
35 inner_attributes, last_line_extendable, last_line_width, mk_sp, outer_attributes,
36 semicolon_for_expr, unicode_str_width, wrap_str,
37};
38use crate::vertical::rewrite_with_alignment;
39use crate::visitor::FmtVisitor;
40
41impl Rewrite for ast::Expr {
42 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
43 self.rewrite_result(context, shape).ok()
44 }
45
46 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
47 format_expr(self, ExprType::SubExpression, context, shape)
48 }
49}
50
51#[derive(Copy, Clone, PartialEq)]
52pub(crate) enum ExprType {
53 Statement,
54 SubExpression,
55}
56
57pub(crate) fn lit_ends_in_dot(lit: &Lit) -> bool {
58 matches!(lit, Lit { kind: LitKind::Float, suffix: None, symbol } if symbol.as_str().ends_with('.'))
59}
60
61pub(crate) fn format_expr(
62 expr: &ast::Expr,
63 expr_type: ExprType,
64 context: &RewriteContext<'_>,
65 shape: Shape,
66) -> RewriteResult {
67 skip_out_of_file_lines_range_err!(context, expr.span);
68
69 if contains_skip(&*expr.attrs) {
70 return Ok(context.snippet(expr.span()).to_owned());
71 }
72 let shape = if expr_type == ExprType::Statement && semicolon_for_expr(context, expr) {
73 shape.sub_width(1).max_width_error(shape.width, expr.span)?
74 } else {
75 shape
76 };
77
78 let expr_rw = match expr.kind {
79 ast::ExprKind::Array(ref expr_vec) => rewrite_array(
80 "",
81 expr_vec.iter(),
82 expr.span,
83 context,
84 shape,
85 choose_separator_tactic(context, expr.span),
86 None,
87 ),
88 ast::ExprKind::Lit(token_lit) => {
89 if let Ok(expr_rw) = rewrite_literal(context, token_lit, expr.span, shape) {
90 Ok(expr_rw)
91 } else {
92 if let LitKind::StrRaw(_) = token_lit.kind {
93 Ok(context.snippet(expr.span).trim().into())
94 } else {
95 Err(RewriteError::Unknown)
96 }
97 }
98 }
99 ast::ExprKind::Call(ref callee, ref args) => {
100 let inner_span = mk_sp(callee.span.hi(), expr.span.hi());
101 let callee_str = callee.rewrite_result(context, shape)?;
102 rewrite_call(context, &callee_str, args, inner_span, shape)
103 }
104 ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, shape, expr.span),
105 ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
106 rewrite_all_pairs(expr, shape, context).or_else(|_| {
108 rewrite_pair(
109 &**lhs,
110 &**rhs,
111 PairParts::infix(&format!(" {} ", context.snippet(op.span))),
112 context,
113 shape,
114 context.config.binop_separator(),
115 )
116 })
117 }
118 ast::ExprKind::Unary(op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape),
119 ast::ExprKind::Struct(ref struct_expr) => {
120 let ast::StructExpr {
121 qself,
122 fields,
123 path,
124 rest,
125 } = &**struct_expr;
126 rewrite_struct_lit(
127 context,
128 path,
129 qself,
130 fields,
131 rest,
132 &expr.attrs,
133 expr.span,
134 shape,
135 )
136 }
137 ast::ExprKind::Tup(ref items) => {
138 rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1)
139 }
140 ast::ExprKind::Use(_, _) => {
141 Ok(context.snippet(expr.span()).to_owned())
143 }
144 ast::ExprKind::Let(ref pat, ref expr, _span, _) => rewrite_let(context, shape, pat, expr),
145 ast::ExprKind::If(..)
146 | ast::ExprKind::ForLoop { .. }
147 | ast::ExprKind::Loop(..)
148 | ast::ExprKind::While(..) => to_control_flow(expr, expr_type)
149 .unknown_error()
150 .and_then(|control_flow| control_flow.rewrite_result(context, shape)),
151 ast::ExprKind::ConstBlock(ref anon_const) => {
152 let rewrite = match anon_const.value.kind {
153 ast::ExprKind::Block(ref block, opt_label) => {
154 rewrite_block(block, Some(&expr.attrs), opt_label, context, shape)?
159 }
160 _ => anon_const.rewrite_result(context, shape)?,
161 };
162 Ok(format!("const {}", rewrite))
163 }
164 ast::ExprKind::Block(ref block, opt_label) => {
165 match expr_type {
166 ExprType::Statement => {
167 if is_unsafe_block(block) {
168 rewrite_block(block, Some(&expr.attrs), opt_label, context, shape)
169 } else if let Some(rw) =
170 rewrite_empty_block(context, block, Some(&expr.attrs), opt_label, "", shape)
171 {
172 Ok(rw)
174 } else {
175 let prefix = block_prefix(context, block, shape)?;
176
177 rewrite_block_with_visitor(
178 context,
179 &prefix,
180 block,
181 Some(&expr.attrs),
182 opt_label,
183 shape,
184 true,
185 )
186 }
187 }
188 ExprType::SubExpression => {
189 rewrite_block(block, Some(&expr.attrs), opt_label, context, shape)
190 }
191 }
192 }
193 ast::ExprKind::Match(ref cond, ref arms, kind) => {
194 rewrite_match(context, cond, arms, shape, expr.span, &expr.attrs, kind)
195 }
196 ast::ExprKind::Path(ref qself, ref path) => {
197 rewrite_path(context, PathContext::Expr, qself, path, shape)
198 }
199 ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
200 rewrite_assignment(context, lhs, rhs, None, shape)
201 }
202 ast::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => {
203 rewrite_assignment(context, lhs, rhs, Some(op), shape)
204 }
205 ast::ExprKind::Continue(ref opt_label) => {
206 let id_str = match *opt_label {
207 Some(label) => format!(" {}", label.ident),
208 None => String::new(),
209 };
210 Ok(format!("continue{id_str}"))
211 }
212 ast::ExprKind::Break(ref opt_label, ref opt_expr) => {
213 let id_str = match *opt_label {
214 Some(label) => format!(" {}", label.ident),
215 None => String::new(),
216 };
217
218 if let Some(ref expr) = *opt_expr {
219 rewrite_unary_prefix(context, &format!("break{id_str} "), &**expr, shape)
220 } else {
221 Ok(format!("break{id_str}"))
222 }
223 }
224 ast::ExprKind::Yield(ast::YieldKind::Prefix(ref opt_expr)) => {
225 if let Some(ref expr) = *opt_expr {
226 rewrite_unary_prefix(context, "yield ", &**expr, shape)
227 } else {
228 Ok("yield".to_string())
229 }
230 }
231 ast::ExprKind::Closure(ref cl) => closures::rewrite_closure(
232 &cl.binder,
233 cl.constness,
234 cl.capture_clause,
235 &cl.coroutine_kind,
236 cl.movability,
237 &cl.fn_decl,
238 &cl.body,
239 expr.span,
240 context,
241 shape,
242 ),
243 ast::ExprKind::Try(..)
244 | ast::ExprKind::Field(..)
245 | ast::ExprKind::MethodCall(..)
246 | ast::ExprKind::Await(_, _)
247 | ast::ExprKind::Yield(ast::YieldKind::Postfix(_)) => rewrite_chain(expr, context, shape),
248 ast::ExprKind::MacCall(ref mac) => {
249 rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|_| {
250 wrap_str(
251 context.snippet(expr.span).to_owned(),
252 context.config.max_width(),
253 shape,
254 )
255 .max_width_error(shape.width, expr.span)
256 })
257 }
258 ast::ExprKind::Ret(None) => Ok("return".to_owned()),
259 ast::ExprKind::Ret(Some(ref expr)) => {
260 rewrite_unary_prefix(context, "return ", &**expr, shape)
261 }
262 ast::ExprKind::Become(ref expr) => rewrite_unary_prefix(context, "become ", &**expr, shape),
263 ast::ExprKind::Yeet(None) => Ok("do yeet".to_owned()),
264 ast::ExprKind::Yeet(Some(ref expr)) => {
265 rewrite_unary_prefix(context, "do yeet ", &**expr, shape)
266 }
267 ast::ExprKind::AddrOf(borrow_kind, mutability, ref expr) => {
268 rewrite_expr_addrof(context, borrow_kind, mutability, expr, shape)
269 }
270 ast::ExprKind::Cast(ref expr, ref ty) => rewrite_pair(
271 &**expr,
272 &**ty,
273 PairParts::infix(" as "),
274 context,
275 shape,
276 SeparatorPlace::Front,
277 ),
278 ast::ExprKind::Index(ref expr, ref index, _) => {
279 rewrite_index(&**expr, &**index, context, shape)
280 }
281 ast::ExprKind::Repeat(ref expr, ref repeats) => rewrite_pair(
282 &**expr,
283 &*repeats.value,
284 PairParts::new("[", "; ", "]"),
285 context,
286 shape,
287 SeparatorPlace::Back,
288 ),
289 ast::ExprKind::Range(ref lhs, ref rhs, limits) => {
290 let delim = match limits {
291 ast::RangeLimits::HalfOpen => "..",
292 ast::RangeLimits::Closed => "..=",
293 };
294
295 fn needs_space_before_range(context: &RewriteContext<'_>, lhs: &ast::Expr) -> bool {
296 match lhs.kind {
297 ast::ExprKind::Lit(token_lit) => lit_ends_in_dot(&token_lit),
298 ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr),
299 ast::ExprKind::Binary(_, _, ref rhs_expr) => {
300 needs_space_before_range(context, rhs_expr)
301 }
302 _ => false,
303 }
304 }
305
306 fn needs_space_after_range(rhs: &ast::Expr) -> bool {
307 matches!(rhs.kind, ast::ExprKind::Range(None, _, _))
313 }
314
315 let default_sp_delim = |lhs: Option<&ast::Expr>, rhs: Option<&ast::Expr>| {
316 let space_if = |b: bool| if b { " " } else { "" };
317
318 format!(
319 "{}{}{}",
320 lhs.map_or("", |lhs| space_if(needs_space_before_range(context, lhs))),
321 delim,
322 rhs.map_or("", |rhs| space_if(needs_space_after_range(rhs))),
323 )
324 };
325
326 match (lhs.as_ref().map(|x| &**x), rhs.as_ref().map(|x| &**x)) {
327 (Some(lhs), Some(rhs)) => {
328 let sp_delim = if context.config.spaces_around_ranges() {
329 format!(" {delim} ")
330 } else {
331 default_sp_delim(Some(lhs), Some(rhs))
332 };
333 rewrite_pair(
334 &*lhs,
335 &*rhs,
336 PairParts::infix(&sp_delim),
337 context,
338 shape,
339 context.config.binop_separator(),
340 )
341 }
342 (None, Some(rhs)) => {
343 let sp_delim = if context.config.spaces_around_ranges() {
344 format!("{delim} ")
345 } else {
346 default_sp_delim(None, Some(rhs))
347 };
348 rewrite_unary_prefix(context, &sp_delim, &*rhs, shape)
349 }
350 (Some(lhs), None) => {
351 let sp_delim = if context.config.spaces_around_ranges() {
352 format!(" {delim}")
353 } else {
354 default_sp_delim(Some(lhs), None)
355 };
356 rewrite_unary_suffix(context, &sp_delim, &*lhs, shape)
357 }
358 (None, None) => Ok(delim.to_owned()),
359 }
360 }
361 ast::ExprKind::InlineAsm(..) => Ok(context.snippet(expr.span).to_owned()),
366 ast::ExprKind::TryBlock(ref block) => {
367 if let rw @ Ok(_) =
368 rewrite_single_line_block(context, "try ", block, Some(&expr.attrs), None, shape)
369 {
370 rw
371 } else {
372 let budget = shape.width.saturating_sub(9);
374 Ok(format!(
375 "{}{}",
376 "try ",
377 rewrite_block(
378 block,
379 Some(&expr.attrs),
380 None,
381 context,
382 Shape::legacy(budget, shape.indent)
383 )?
384 ))
385 }
386 }
387 ast::ExprKind::Gen(capture_by, ref block, ref kind, _) => {
388 let mover = if matches!(capture_by, ast::CaptureBy::Value { .. }) {
389 "move "
390 } else {
391 ""
392 };
393 if let rw @ Ok(_) = rewrite_single_line_block(
394 context,
395 format!("{kind} {mover}").as_str(),
396 block,
397 Some(&expr.attrs),
398 None,
399 shape,
400 ) {
401 rw
402 } else {
403 let budget = shape.width.saturating_sub(6);
405 Ok(format!(
406 "{kind} {mover}{}",
407 rewrite_block(
408 block,
409 Some(&expr.attrs),
410 None,
411 context,
412 Shape::legacy(budget, shape.indent)
413 )?
414 ))
415 }
416 }
417 ast::ExprKind::Underscore => Ok("_".to_owned()),
418 ast::ExprKind::FormatArgs(..)
419 | ast::ExprKind::Type(..)
420 | ast::ExprKind::IncludedBytes(..)
421 | ast::ExprKind::OffsetOf(..)
422 | ast::ExprKind::UnsafeBinderCast(..) => {
423 Err(RewriteError::Unknown)
428 }
429 ast::ExprKind::Err(_) | ast::ExprKind::Dummy => Err(RewriteError::Unknown),
430 };
431
432 expr_rw
433 .map(|expr_str| recover_comment_removed(expr_str, expr.span, context))
434 .and_then(|expr_str| {
435 let attrs = outer_attributes(&expr.attrs);
436 let attrs_str = attrs.rewrite_result(context, shape)?;
437 let span = mk_sp(
438 attrs.last().map_or(expr.span.lo(), |attr| attr.span.hi()),
439 expr.span.lo(),
440 );
441 combine_strs_with_missing_comments(context, &attrs_str, &expr_str, span, shape, false)
442 })
443}
444
445pub(crate) fn rewrite_array<'a, T: 'a + IntoOverflowableItem<'a>>(
446 name: &'a str,
447 exprs: impl Iterator<Item = &'a T>,
448 span: Span,
449 context: &'a RewriteContext<'_>,
450 shape: Shape,
451 force_separator_tactic: Option<SeparatorTactic>,
452 delim_token: Option<Delimiter>,
453) -> RewriteResult {
454 overflow::rewrite_with_square_brackets(
455 context,
456 name,
457 exprs,
458 shape,
459 span,
460 force_separator_tactic,
461 delim_token,
462 )
463}
464
465fn rewrite_empty_block(
466 context: &RewriteContext<'_>,
467 block: &ast::Block,
468 attrs: Option<&[ast::Attribute]>,
469 label: Option<ast::Label>,
470 prefix: &str,
471 shape: Shape,
472) -> Option<String> {
473 if block_has_statements(block) {
474 return None;
475 }
476
477 let label_str = rewrite_label(context, label);
478 if attrs.map_or(false, |a| !inner_attributes(a).is_empty()) {
479 return None;
480 }
481
482 if !block_contains_comment(context, block) && shape.width >= 2 {
483 return Some(format!("{prefix}{label_str}{{}}"));
484 }
485
486 let user_str = context.snippet(block.span);
488 let user_str = user_str.trim();
489 if user_str.starts_with('{') && user_str.ends_with('}') {
490 let comment_str = user_str[1..user_str.len() - 1].trim();
491 if block.stmts.is_empty()
492 && !comment_str.contains('\n')
493 && !comment_str.starts_with("//")
494 && comment_str.len() + 4 <= shape.width
495 {
496 return Some(format!("{prefix}{label_str}{{ {comment_str} }}"));
497 }
498 }
499
500 None
501}
502
503fn block_prefix(context: &RewriteContext<'_>, block: &ast::Block, shape: Shape) -> RewriteResult {
504 Ok(match block.rules {
505 ast::BlockCheckMode::Unsafe(..) => {
506 let snippet = context.snippet(block.span);
507 let open_pos = snippet.find_uncommented("{").unknown_error()?;
508 let trimmed = &snippet[6..open_pos].trim();
510
511 if !trimmed.is_empty() {
512 let budget = shape
514 .width
515 .checked_sub(9)
516 .max_width_error(shape.width, block.span)?;
517 format!(
518 "unsafe {} ",
519 rewrite_comment(
520 trimmed,
521 true,
522 Shape::legacy(budget, shape.indent + 7),
523 context.config,
524 )?
525 )
526 } else {
527 "unsafe ".to_owned()
528 }
529 }
530 ast::BlockCheckMode::Default => String::new(),
531 })
532}
533
534fn rewrite_single_line_block(
535 context: &RewriteContext<'_>,
536 prefix: &str,
537 block: &ast::Block,
538 attrs: Option<&[ast::Attribute]>,
539 label: Option<ast::Label>,
540 shape: Shape,
541) -> RewriteResult {
542 if let Some(block_expr) = stmt::Stmt::from_simple_block(context, block, attrs) {
543 let expr_shape = shape
544 .offset_left(last_line_width(prefix))
545 .max_width_error(shape.width, block_expr.span())?;
546 let expr_str = block_expr.rewrite_result(context, expr_shape)?;
547 let label_str = rewrite_label(context, label);
548 let result = format!("{prefix}{label_str}{{ {expr_str} }}");
549 if result.len() <= shape.width && !result.contains('\n') {
550 return Ok(result);
551 }
552 }
553 Err(RewriteError::Unknown)
554}
555
556pub(crate) fn rewrite_block_with_visitor(
557 context: &RewriteContext<'_>,
558 prefix: &str,
559 block: &ast::Block,
560 attrs: Option<&[ast::Attribute]>,
561 label: Option<ast::Label>,
562 shape: Shape,
563 has_braces: bool,
564) -> RewriteResult {
565 if let Some(rw_str) = rewrite_empty_block(context, block, attrs, label, prefix, shape) {
566 return Ok(rw_str);
567 }
568
569 let mut visitor = FmtVisitor::from_context(context);
570 visitor.block_indent = shape.indent;
571 visitor.is_if_else_block = context.is_if_else_block();
572 match (block.rules, label) {
573 (ast::BlockCheckMode::Unsafe(..), _) | (ast::BlockCheckMode::Default, Some(_)) => {
574 let snippet = context.snippet(block.span);
575 let open_pos = snippet.find_uncommented("{").unknown_error()?;
576 visitor.last_pos = block.span.lo() + BytePos(open_pos as u32)
577 }
578 (ast::BlockCheckMode::Default, None) => visitor.last_pos = block.span.lo(),
579 }
580
581 let inner_attrs = attrs.map(inner_attributes);
582 let label_str = rewrite_label(context, label);
583 visitor.visit_block(block, inner_attrs.as_deref(), has_braces);
584 let visitor_context = visitor.get_context();
585 context
586 .skipped_range
587 .borrow_mut()
588 .append(&mut visitor_context.skipped_range.borrow_mut());
589 Ok(format!("{}{}{}", prefix, label_str, visitor.buffer))
590}
591
592impl Rewrite for ast::Block {
593 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
594 self.rewrite_result(context, shape).ok()
595 }
596
597 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
598 rewrite_block(self, None, None, context, shape)
599 }
600}
601
602fn rewrite_block(
603 block: &ast::Block,
604 attrs: Option<&[ast::Attribute]>,
605 label: Option<ast::Label>,
606 context: &RewriteContext<'_>,
607 shape: Shape,
608) -> RewriteResult {
609 rewrite_block_inner(block, attrs, label, true, context, shape)
610}
611
612fn rewrite_block_inner(
613 block: &ast::Block,
614 attrs: Option<&[ast::Attribute]>,
615 label: Option<ast::Label>,
616 allow_single_line: bool,
617 context: &RewriteContext<'_>,
618 shape: Shape,
619) -> RewriteResult {
620 let prefix = block_prefix(context, block, shape)?;
621
622 if let Some(rw_str) = rewrite_empty_block(context, block, attrs, label, &prefix, shape) {
625 return Ok(rw_str);
626 }
627
628 let result_str =
629 rewrite_block_with_visitor(context, &prefix, block, attrs, label, shape, true)?;
630 if allow_single_line && result_str.lines().count() <= 3 {
631 if let rw @ Ok(_) = rewrite_single_line_block(context, &prefix, block, attrs, label, shape)
632 {
633 return rw;
634 }
635 }
636 Ok(result_str)
637}
638
639pub(crate) fn rewrite_let_else_block(
641 block: &ast::Block,
642 allow_single_line: bool,
643 context: &RewriteContext<'_>,
644 shape: Shape,
645) -> RewriteResult {
646 rewrite_block_inner(block, None, None, allow_single_line, context, shape)
647}
648
649pub(crate) fn rewrite_cond(
651 context: &RewriteContext<'_>,
652 expr: &ast::Expr,
653 shape: Shape,
654) -> Option<String> {
655 match expr.kind {
656 ast::ExprKind::Match(ref cond, _, MatchKind::Prefix) => {
657 let cond_shape = match context.config.indent_style() {
659 IndentStyle::Visual => shape.shrink_left(6).and_then(|s| s.sub_width(2))?,
660 IndentStyle::Block => shape.offset_left(8)?,
661 };
662 cond.rewrite(context, cond_shape)
663 }
664 _ => to_control_flow(expr, ExprType::SubExpression).and_then(|control_flow| {
665 let alt_block_sep =
666 String::from("\n") + &shape.indent.block_only().to_string(context.config);
667 control_flow
668 .rewrite_cond(context, shape, &alt_block_sep)
669 .ok()
670 .map(|rw| rw.0)
671 }),
672 }
673}
674
675#[derive(Debug)]
677struct ControlFlow<'a> {
678 cond: Option<&'a ast::Expr>,
679 block: &'a ast::Block,
680 else_block: Option<&'a ast::Expr>,
681 label: Option<ast::Label>,
682 pat: Option<&'a ast::Pat>,
683 keyword: &'a str,
684 matcher: &'a str,
685 connector: &'a str,
686 allow_single_line: bool,
687 nested_if: bool,
689 span: Span,
690}
691
692fn extract_pats_and_cond(expr: &ast::Expr) -> (Option<&ast::Pat>, &ast::Expr) {
693 match expr.kind {
694 ast::ExprKind::Let(ref pat, ref cond, _, _) => (Some(pat), cond),
695 _ => (None, expr),
696 }
697}
698
699fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option<ControlFlow<'_>> {
701 match expr.kind {
702 ast::ExprKind::If(ref cond, ref if_block, ref else_block) => {
703 let (pat, cond) = extract_pats_and_cond(cond);
704 Some(ControlFlow::new_if(
705 cond,
706 pat,
707 if_block,
708 else_block.as_ref().map(|e| &**e),
709 expr_type == ExprType::SubExpression,
710 false,
711 expr.span,
712 ))
713 }
714 ast::ExprKind::ForLoop {
715 ref pat,
716 ref iter,
717 ref body,
718 label,
719 kind,
720 } => Some(ControlFlow::new_for(
721 pat, iter, body, label, expr.span, kind,
722 )),
723 ast::ExprKind::Loop(ref block, label, _) => {
724 Some(ControlFlow::new_loop(block, label, expr.span))
725 }
726 ast::ExprKind::While(ref cond, ref block, label) => {
727 let (pat, cond) = extract_pats_and_cond(cond);
728 Some(ControlFlow::new_while(pat, cond, block, label, expr.span))
729 }
730 _ => None,
731 }
732}
733
734fn choose_matcher(pat: Option<&ast::Pat>) -> &'static str {
735 pat.map_or("", |_| "let")
736}
737
738impl<'a> ControlFlow<'a> {
739 fn new_if(
740 cond: &'a ast::Expr,
741 pat: Option<&'a ast::Pat>,
742 block: &'a ast::Block,
743 else_block: Option<&'a ast::Expr>,
744 allow_single_line: bool,
745 nested_if: bool,
746 span: Span,
747 ) -> ControlFlow<'a> {
748 let matcher = choose_matcher(pat);
749 ControlFlow {
750 cond: Some(cond),
751 block,
752 else_block,
753 label: None,
754 pat,
755 keyword: "if",
756 matcher,
757 connector: " =",
758 allow_single_line,
759 nested_if,
760 span,
761 }
762 }
763
764 fn new_loop(block: &'a ast::Block, label: Option<ast::Label>, span: Span) -> ControlFlow<'a> {
765 ControlFlow {
766 cond: None,
767 block,
768 else_block: None,
769 label,
770 pat: None,
771 keyword: "loop",
772 matcher: "",
773 connector: "",
774 allow_single_line: false,
775 nested_if: false,
776 span,
777 }
778 }
779
780 fn new_while(
781 pat: Option<&'a ast::Pat>,
782 cond: &'a ast::Expr,
783 block: &'a ast::Block,
784 label: Option<ast::Label>,
785 span: Span,
786 ) -> ControlFlow<'a> {
787 let matcher = choose_matcher(pat);
788 ControlFlow {
789 cond: Some(cond),
790 block,
791 else_block: None,
792 label,
793 pat,
794 keyword: "while",
795 matcher,
796 connector: " =",
797 allow_single_line: false,
798 nested_if: false,
799 span,
800 }
801 }
802
803 fn new_for(
804 pat: &'a ast::Pat,
805 cond: &'a ast::Expr,
806 block: &'a ast::Block,
807 label: Option<ast::Label>,
808 span: Span,
809 kind: ForLoopKind,
810 ) -> ControlFlow<'a> {
811 ControlFlow {
812 cond: Some(cond),
813 block,
814 else_block: None,
815 label,
816 pat: Some(pat),
817 keyword: match kind {
818 ForLoopKind::For => "for",
819 ForLoopKind::ForAwait => "for await",
820 },
821 matcher: "",
822 connector: " in",
823 allow_single_line: false,
824 nested_if: false,
825 span,
826 }
827 }
828
829 fn rewrite_single_line(
830 &self,
831 pat_expr_str: &str,
832 context: &RewriteContext<'_>,
833 width: usize,
834 ) -> Option<String> {
835 assert!(self.allow_single_line);
836 let else_block = self.else_block?;
837 let fixed_cost = self.keyword.len() + " { } else { }".len();
838
839 if let ast::ExprKind::Block(ref else_node, _) = else_block.kind {
840 let (if_expr, else_expr) = match (
841 stmt::Stmt::from_simple_block(context, self.block, None),
842 stmt::Stmt::from_simple_block(context, else_node, None),
843 pat_expr_str.contains('\n'),
844 ) {
845 (Some(if_expr), Some(else_expr), false) => (if_expr, else_expr),
846 _ => return None,
847 };
848
849 let new_width = width.checked_sub(pat_expr_str.len() + fixed_cost)?;
850 let if_str = if_expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
851
852 let new_width = new_width.checked_sub(if_str.len())?;
853 let else_str = else_expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
854
855 if if_str.contains('\n') || else_str.contains('\n') {
856 return None;
857 }
858
859 let result = format!(
860 "{} {} {{ {} }} else {{ {} }}",
861 self.keyword, pat_expr_str, if_str, else_str
862 );
863
864 if result.len() <= width {
865 return Some(result);
866 }
867 }
868
869 None
870 }
871}
872
873fn last_line_offsetted(start_column: usize, pat_str: &str) -> bool {
876 let mut leading_whitespaces = 0;
877 for c in pat_str.chars().rev() {
878 match c {
879 '\n' => break,
880 _ if c.is_whitespace() => leading_whitespaces += 1,
881 _ => leading_whitespaces = 0,
882 }
883 }
884 leading_whitespaces > start_column
885}
886
887impl<'a> ControlFlow<'a> {
888 fn rewrite_pat_expr(
889 &self,
890 context: &RewriteContext<'_>,
891 expr: &ast::Expr,
892 shape: Shape,
893 offset: usize,
894 ) -> RewriteResult {
895 debug!("rewrite_pat_expr {:?} {:?} {:?}", shape, self.pat, expr);
896
897 let cond_shape = shape
898 .offset_left(offset)
899 .max_width_error(shape.width, expr.span)?;
900 if let Some(pat) = self.pat {
901 let matcher = if self.matcher.is_empty() {
902 self.matcher.to_owned()
903 } else {
904 format!("{} ", self.matcher)
905 };
906 let pat_shape = cond_shape
907 .offset_left(matcher.len())
908 .and_then(|s| s.sub_width(self.connector.len()))
909 .max_width_error(cond_shape.width, pat.span)?;
910 let pat_string = pat.rewrite_result(context, pat_shape)?;
911 let comments_lo = context
912 .snippet_provider
913 .span_after(self.span.with_lo(pat.span.hi()), self.connector.trim());
914 let comments_span = mk_sp(comments_lo, expr.span.lo());
915 return rewrite_assign_rhs_with_comments(
916 context,
917 &format!("{}{}{}", matcher, pat_string, self.connector),
918 expr,
919 cond_shape,
920 &RhsAssignKind::Expr(&expr.kind, expr.span),
921 RhsTactics::Default,
922 comments_span,
923 true,
924 );
925 }
926
927 let expr_rw = expr.rewrite_result(context, cond_shape);
928 if self.keyword == "if" || expr_rw.is_ok() {
931 return expr_rw;
932 }
933
934 let nested_shape = shape
936 .block_indent(context.config.tab_spaces())
937 .with_max_width(context.config);
938 let nested_indent_str = nested_shape.indent.to_string_with_newline(context.config);
939 expr.rewrite_result(context, nested_shape)
940 .map(|expr_rw| format!("{}{}", nested_indent_str, expr_rw))
941 }
942
943 fn rewrite_cond(
944 &self,
945 context: &RewriteContext<'_>,
946 shape: Shape,
947 alt_block_sep: &str,
948 ) -> Result<(String, usize), RewriteError> {
949 let new_width = context.budget(shape.used_width());
952 let fresh_shape = Shape {
953 width: new_width,
954 ..shape
955 };
956 let constr_shape = if self.nested_if {
957 fresh_shape
960 .offset_left(7)
961 .max_width_error(fresh_shape.width, self.span)?
962 } else {
963 fresh_shape
964 };
965
966 let label_string = rewrite_label(context, self.label);
967 let offset = self.keyword.len() + label_string.len() + 1;
969
970 let pat_expr_string = match self.cond {
971 Some(cond) => self.rewrite_pat_expr(context, cond, constr_shape, offset)?,
972 None => String::new(),
973 };
974
975 let brace_overhead =
976 if context.config.control_brace_style() != ControlBraceStyle::AlwaysNextLine {
977 2
979 } else {
980 0
981 };
982 let one_line_budget = context
983 .config
984 .max_width()
985 .saturating_sub(constr_shape.used_width() + offset + brace_overhead);
986 let force_newline_brace = (pat_expr_string.contains('\n')
987 || pat_expr_string.len() > one_line_budget)
988 && (!last_line_extendable(&pat_expr_string)
989 || last_line_offsetted(shape.used_width(), &pat_expr_string));
990
991 if self.allow_single_line && context.config.single_line_if_else_max_width() > 0 {
993 let trial = self.rewrite_single_line(&pat_expr_string, context, shape.width);
994
995 if let Some(cond_str) = trial {
996 if cond_str.len() <= context.config.single_line_if_else_max_width() {
997 return Ok((cond_str, 0));
998 }
999 }
1000 }
1001
1002 let cond_span = if let Some(cond) = self.cond {
1003 cond.span
1004 } else {
1005 mk_sp(self.block.span.lo(), self.block.span.lo())
1006 };
1007
1008 let lo = self
1011 .label
1012 .map_or(self.span.lo(), |label| label.ident.span.hi());
1013 let between_kwd_cond = mk_sp(
1014 context
1015 .snippet_provider
1016 .span_after(mk_sp(lo, self.span.hi()), self.keyword.trim()),
1017 if self.pat.is_none() {
1018 cond_span.lo()
1019 } else if self.matcher.is_empty() {
1020 self.pat.unwrap().span.lo()
1021 } else {
1022 context
1023 .snippet_provider
1024 .span_before(self.span, self.matcher.trim())
1025 },
1026 );
1027
1028 let between_kwd_cond_comment = extract_comment(between_kwd_cond, context, shape);
1029
1030 let after_cond_comment =
1031 extract_comment(mk_sp(cond_span.hi(), self.block.span.lo()), context, shape);
1032
1033 let block_sep = if self.cond.is_none() && between_kwd_cond_comment.is_some() {
1034 ""
1035 } else if context.config.control_brace_style() == ControlBraceStyle::AlwaysNextLine
1036 || force_newline_brace
1037 {
1038 alt_block_sep
1039 } else {
1040 " "
1041 };
1042
1043 let used_width = if pat_expr_string.contains('\n') {
1044 last_line_width(&pat_expr_string)
1045 } else {
1046 label_string.len() + self.keyword.len() + pat_expr_string.len() + 2
1048 };
1049
1050 Ok((
1051 format!(
1052 "{}{}{}{}{}",
1053 label_string,
1054 self.keyword,
1055 between_kwd_cond_comment.as_ref().map_or(
1056 if pat_expr_string.is_empty() || pat_expr_string.starts_with('\n') {
1057 ""
1058 } else {
1059 " "
1060 },
1061 |s| &**s,
1062 ),
1063 pat_expr_string,
1064 after_cond_comment.as_ref().map_or(block_sep, |s| &**s)
1065 ),
1066 used_width,
1067 ))
1068 }
1069}
1070
1071pub(crate) fn rewrite_else_kw_with_comments(
1080 force_newline_else: bool,
1081 is_last: bool,
1082 context: &RewriteContext<'_>,
1083 span: Span,
1084 shape: Shape,
1085) -> String {
1086 let else_kw_lo = context.snippet_provider.span_before(span, "else");
1087 let before_else_kw = mk_sp(span.lo(), else_kw_lo);
1088 let before_else_kw_comment = extract_comment(before_else_kw, context, shape);
1089
1090 let else_kw_hi = context.snippet_provider.span_after(span, "else");
1091 let after_else_kw = mk_sp(else_kw_hi, span.hi());
1092 let after_else_kw_comment = extract_comment(after_else_kw, context, shape);
1093
1094 let newline_sep = &shape.indent.to_string_with_newline(context.config);
1095 let before_sep = match context.config.control_brace_style() {
1096 _ if force_newline_else => newline_sep.as_ref(),
1097 ControlBraceStyle::AlwaysNextLine | ControlBraceStyle::ClosingNextLine => {
1098 newline_sep.as_ref()
1099 }
1100 ControlBraceStyle::AlwaysSameLine => " ",
1101 };
1102 let after_sep = match context.config.control_brace_style() {
1103 ControlBraceStyle::AlwaysNextLine if is_last => newline_sep.as_ref(),
1104 _ => " ",
1105 };
1106
1107 format!(
1108 "{}else{}",
1109 before_else_kw_comment.as_ref().map_or(before_sep, |s| &**s),
1110 after_else_kw_comment.as_ref().map_or(after_sep, |s| &**s),
1111 )
1112}
1113
1114impl<'a> Rewrite for ControlFlow<'a> {
1115 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1116 self.rewrite_result(context, shape).ok()
1117 }
1118
1119 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
1120 debug!("ControlFlow::rewrite {:?} {:?}", self, shape);
1121
1122 let alt_block_sep = &shape.indent.to_string_with_newline(context.config);
1123 let (cond_str, used_width) = self.rewrite_cond(context, shape, alt_block_sep)?;
1124 if used_width == 0 {
1126 return Ok(cond_str);
1127 }
1128
1129 let block_width = shape.width.saturating_sub(used_width);
1130 let block_width = if self.else_block.is_some() || self.nested_if {
1133 min(1, block_width)
1134 } else {
1135 block_width
1136 };
1137 let block_shape = Shape {
1138 width: block_width,
1139 ..shape
1140 };
1141 let block_str = {
1142 let old_val = context.is_if_else_block.replace(self.else_block.is_some());
1143 let result =
1144 rewrite_block_with_visitor(context, "", self.block, None, None, block_shape, true);
1145 context.is_if_else_block.replace(old_val);
1146 result?
1147 };
1148
1149 let mut result = format!("{cond_str}{block_str}");
1150
1151 if let Some(else_block) = self.else_block {
1152 let shape = Shape::indented(shape.indent, context.config);
1153 let mut last_in_chain = false;
1154 let rewrite = match else_block.kind {
1155 ast::ExprKind::If(ref cond, ref if_block, ref next_else_block) => {
1160 let (pats, cond) = extract_pats_and_cond(cond);
1161 ControlFlow::new_if(
1162 cond,
1163 pats,
1164 if_block,
1165 next_else_block.as_ref().map(|e| &**e),
1166 false,
1167 true,
1168 mk_sp(else_block.span.lo(), self.span.hi()),
1169 )
1170 .rewrite_result(context, shape)
1171 }
1172 _ => {
1173 last_in_chain = true;
1174 let else_shape = Shape {
1177 width: min(1, shape.width),
1178 ..shape
1179 };
1180 format_expr(else_block, ExprType::Statement, context, else_shape)
1181 }
1182 };
1183
1184 let else_kw = rewrite_else_kw_with_comments(
1185 false,
1186 last_in_chain,
1187 context,
1188 self.block.span.between(else_block.span),
1189 shape,
1190 );
1191 result.push_str(&else_kw);
1192 result.push_str(&rewrite?);
1193 }
1194
1195 Ok(result)
1196 }
1197}
1198
1199fn rewrite_label(context: &RewriteContext<'_>, opt_label: Option<ast::Label>) -> Cow<'static, str> {
1200 match opt_label {
1201 Some(label) => Cow::from(format!("{}: ", context.snippet(label.ident.span))),
1202 None => Cow::from(""),
1203 }
1204}
1205
1206fn extract_comment(span: Span, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1207 match rewrite_missing_comment(span, shape, context) {
1208 Ok(ref comment) if !comment.is_empty() => Some(format!(
1209 "{indent}{comment}{indent}",
1210 indent = shape.indent.to_string_with_newline(context.config)
1211 )),
1212 _ => None,
1213 }
1214}
1215
1216pub(crate) fn block_contains_comment(context: &RewriteContext<'_>, block: &ast::Block) -> bool {
1217 contains_comment(context.snippet(block.span))
1218}
1219
1220pub(crate) fn is_simple_block(
1225 context: &RewriteContext<'_>,
1226 block: &ast::Block,
1227 attrs: Option<&[ast::Attribute]>,
1228) -> bool {
1229 block.stmts.len() == 1
1230 && stmt_is_expr(&block.stmts[0])
1231 && !block_contains_comment(context, block)
1232 && attrs.map_or(true, |a| a.is_empty())
1233}
1234
1235pub(crate) fn is_simple_block_stmt(
1238 context: &RewriteContext<'_>,
1239 block: &ast::Block,
1240 attrs: Option<&[ast::Attribute]>,
1241) -> bool {
1242 block.stmts.len() <= 1
1243 && !block_contains_comment(context, block)
1244 && attrs.map_or(true, |a| a.is_empty())
1245}
1246
1247fn block_has_statements(block: &ast::Block) -> bool {
1248 block
1249 .stmts
1250 .iter()
1251 .any(|stmt| !matches!(stmt.kind, ast::StmtKind::Empty))
1252}
1253
1254pub(crate) fn is_empty_block(
1257 context: &RewriteContext<'_>,
1258 block: &ast::Block,
1259 attrs: Option<&[ast::Attribute]>,
1260) -> bool {
1261 !block_has_statements(block)
1262 && !block_contains_comment(context, block)
1263 && attrs.map_or(true, |a| inner_attributes(a).is_empty())
1264}
1265
1266pub(crate) fn stmt_is_expr(stmt: &ast::Stmt) -> bool {
1267 matches!(stmt.kind, ast::StmtKind::Expr(..))
1268}
1269
1270pub(crate) fn is_unsafe_block(block: &ast::Block) -> bool {
1271 matches!(block.rules, ast::BlockCheckMode::Unsafe(..))
1272}
1273
1274pub(crate) fn rewrite_literal(
1275 context: &RewriteContext<'_>,
1276 token_lit: token::Lit,
1277 span: Span,
1278 shape: Shape,
1279) -> RewriteResult {
1280 match token_lit.kind {
1281 token::LitKind::Str => rewrite_string_lit(context, span, shape),
1282 token::LitKind::Integer => rewrite_int_lit(context, token_lit, span, shape),
1283 _ => wrap_str(
1284 context.snippet(span).to_owned(),
1285 context.config.max_width(),
1286 shape,
1287 )
1288 .max_width_error(shape.width, span),
1289 }
1290}
1291
1292fn rewrite_string_lit(context: &RewriteContext<'_>, span: Span, shape: Shape) -> RewriteResult {
1293 let string_lit = context.snippet(span);
1294
1295 if !context.config.format_strings() {
1296 if string_lit
1297 .lines()
1298 .dropping_back(1)
1299 .all(|line| line.ends_with('\\'))
1300 && context.config.style_edition() >= StyleEdition::Edition2024
1301 {
1302 return Ok(string_lit.to_owned());
1303 } else {
1304 return wrap_str(string_lit.to_owned(), context.config.max_width(), shape)
1305 .max_width_error(shape.width, span);
1306 }
1307 }
1308
1309 let str_lit = &string_lit[1..string_lit.len() - 1];
1311
1312 rewrite_string(
1313 str_lit,
1314 &StringFormat::new(shape.visual_indent(0), context.config),
1315 shape.width.saturating_sub(2),
1316 )
1317 .max_width_error(shape.width, span)
1318}
1319
1320fn rewrite_int_lit(
1321 context: &RewriteContext<'_>,
1322 token_lit: token::Lit,
1323 span: Span,
1324 shape: Shape,
1325) -> RewriteResult {
1326 let symbol = token_lit.symbol.as_str();
1327
1328 if let Some(symbol_stripped) = symbol.strip_prefix("0x") {
1329 let hex_lit = match context.config.hex_literal_case() {
1330 HexLiteralCase::Preserve => None,
1331 HexLiteralCase::Upper => Some(symbol_stripped.to_ascii_uppercase()),
1332 HexLiteralCase::Lower => Some(symbol_stripped.to_ascii_lowercase()),
1333 };
1334 if let Some(hex_lit) = hex_lit {
1335 return wrap_str(
1336 format!(
1337 "0x{}{}",
1338 hex_lit,
1339 token_lit.suffix.as_ref().map_or("", |s| s.as_str())
1340 ),
1341 context.config.max_width(),
1342 shape,
1343 )
1344 .max_width_error(shape.width, span);
1345 }
1346 }
1347
1348 wrap_str(
1349 context.snippet(span).to_owned(),
1350 context.config.max_width(),
1351 shape,
1352 )
1353 .max_width_error(shape.width, span)
1354}
1355
1356fn choose_separator_tactic(context: &RewriteContext<'_>, span: Span) -> Option<SeparatorTactic> {
1357 if context.inside_macro() {
1358 if span_ends_with_comma(context, span) {
1359 Some(SeparatorTactic::Always)
1360 } else {
1361 Some(SeparatorTactic::Never)
1362 }
1363 } else {
1364 None
1365 }
1366}
1367
1368pub(crate) fn rewrite_call(
1369 context: &RewriteContext<'_>,
1370 callee: &str,
1371 args: &[ptr::P<ast::Expr>],
1372 span: Span,
1373 shape: Shape,
1374) -> RewriteResult {
1375 overflow::rewrite_with_parens(
1376 context,
1377 callee,
1378 args.iter(),
1379 shape,
1380 span,
1381 context.config.fn_call_width(),
1382 choose_separator_tactic(context, span),
1383 )
1384}
1385
1386pub(crate) fn is_simple_expr(expr: &ast::Expr) -> bool {
1387 match expr.kind {
1388 ast::ExprKind::Lit(..) => true,
1389 ast::ExprKind::Path(ref qself, ref path) => qself.is_none() && path.segments.len() <= 1,
1390 ast::ExprKind::AddrOf(_, _, ref expr)
1391 | ast::ExprKind::Cast(ref expr, _)
1392 | ast::ExprKind::Field(ref expr, _)
1393 | ast::ExprKind::Try(ref expr)
1394 | ast::ExprKind::Unary(_, ref expr) => is_simple_expr(expr),
1395 ast::ExprKind::Index(ref lhs, ref rhs, _) => is_simple_expr(lhs) && is_simple_expr(rhs),
1396 ast::ExprKind::Repeat(ref lhs, ref rhs) => {
1397 is_simple_expr(lhs) && is_simple_expr(&*rhs.value)
1398 }
1399 _ => false,
1400 }
1401}
1402
1403pub(crate) fn is_every_expr_simple(lists: &[OverflowableItem<'_>]) -> bool {
1404 lists.iter().all(OverflowableItem::is_simple)
1405}
1406
1407pub(crate) fn can_be_overflowed_expr(
1408 context: &RewriteContext<'_>,
1409 expr: &ast::Expr,
1410 args_len: usize,
1411) -> bool {
1412 match expr.kind {
1413 _ if !expr.attrs.is_empty() => false,
1414 ast::ExprKind::Match(..) => {
1415 (context.use_block_indent() && args_len == 1)
1416 || (context.config.indent_style() == IndentStyle::Visual && args_len > 1)
1417 || context.config.overflow_delimited_expr()
1418 }
1419 ast::ExprKind::If(..)
1420 | ast::ExprKind::ForLoop { .. }
1421 | ast::ExprKind::Loop(..)
1422 | ast::ExprKind::While(..) => {
1423 context.config.combine_control_expr() && context.use_block_indent() && args_len == 1
1424 }
1425
1426 ast::ExprKind::Gen(..) | ast::ExprKind::Block(..) | ast::ExprKind::Closure(..) => true,
1428
1429 ast::ExprKind::Array(..) | ast::ExprKind::Struct(..) => {
1431 context.config.overflow_delimited_expr()
1432 || (context.use_block_indent() && args_len == 1)
1433 }
1434 ast::ExprKind::MacCall(ref mac) => {
1435 match (mac.args.delim, context.config.overflow_delimited_expr()) {
1436 (Delimiter::Bracket, true) | (Delimiter::Brace, true) => true,
1437 _ => context.use_block_indent() && args_len == 1,
1438 }
1439 }
1440
1441 ast::ExprKind::Call(..) | ast::ExprKind::MethodCall(..) | ast::ExprKind::Tup(..) => {
1443 context.use_block_indent() && args_len == 1
1444 }
1445
1446 ast::ExprKind::AddrOf(_, _, ref expr)
1448 | ast::ExprKind::Try(ref expr)
1449 | ast::ExprKind::Unary(_, ref expr)
1450 | ast::ExprKind::Cast(ref expr, _) => can_be_overflowed_expr(context, expr, args_len),
1451 _ => false,
1452 }
1453}
1454
1455pub(crate) fn is_nested_call(expr: &ast::Expr) -> bool {
1456 match expr.kind {
1457 ast::ExprKind::Call(..) | ast::ExprKind::MacCall(..) => true,
1458 ast::ExprKind::AddrOf(_, _, ref expr)
1459 | ast::ExprKind::Try(ref expr)
1460 | ast::ExprKind::Unary(_, ref expr)
1461 | ast::ExprKind::Cast(ref expr, _) => is_nested_call(expr),
1462 _ => false,
1463 }
1464}
1465
1466pub(crate) fn span_ends_with_comma(context: &RewriteContext<'_>, span: Span) -> bool {
1470 let mut result: bool = Default::default();
1471 let mut prev_char: char = Default::default();
1472 let closing_delimiters = &[')', '}', ']'];
1473
1474 for (kind, c) in CharClasses::new(context.snippet(span).chars()) {
1475 match c {
1476 _ if kind.is_comment() || c.is_whitespace() => continue,
1477 c if closing_delimiters.contains(&c) => {
1478 result &= !closing_delimiters.contains(&prev_char);
1479 }
1480 ',' => result = true,
1481 _ => result = false,
1482 }
1483 prev_char = c;
1484 }
1485
1486 result
1487}
1488
1489pub(crate) fn rewrite_paren(
1490 context: &RewriteContext<'_>,
1491 mut subexpr: &ast::Expr,
1492 shape: Shape,
1493 mut span: Span,
1494) -> RewriteResult {
1495 debug!("rewrite_paren, shape: {:?}", shape);
1496
1497 let mut pre_span;
1499 let mut post_span;
1500 let mut pre_comment;
1501 let mut post_comment;
1502 let remove_nested_parens = context.config.remove_nested_parens();
1503 loop {
1504 pre_span = mk_sp(span.lo() + BytePos(1), subexpr.span().lo());
1506 post_span = mk_sp(subexpr.span.hi(), span.hi() - BytePos(1));
1507 pre_comment = rewrite_missing_comment(pre_span, shape, context)?;
1508 post_comment = rewrite_missing_comment(post_span, shape, context)?;
1509
1510 if let ast::ExprKind::Paren(ref subsubexpr) = subexpr.kind {
1512 if remove_nested_parens && pre_comment.is_empty() && post_comment.is_empty() {
1513 span = subexpr.span;
1514 subexpr = subsubexpr;
1515 continue;
1516 }
1517 }
1518
1519 break;
1520 }
1521
1522 let sub_shape = shape
1524 .offset_left(1)
1525 .and_then(|s| s.sub_width(1))
1526 .max_width_error(shape.width, span)?;
1527 let subexpr_str = subexpr.rewrite_result(context, sub_shape)?;
1528 let fits_single_line = !pre_comment.contains("//") && !post_comment.contains("//");
1529 if fits_single_line {
1530 Ok(format!("({pre_comment}{subexpr_str}{post_comment})"))
1531 } else {
1532 rewrite_paren_in_multi_line(context, subexpr, shape, pre_span, post_span)
1533 }
1534}
1535
1536fn rewrite_paren_in_multi_line(
1537 context: &RewriteContext<'_>,
1538 subexpr: &ast::Expr,
1539 shape: Shape,
1540 pre_span: Span,
1541 post_span: Span,
1542) -> RewriteResult {
1543 let nested_indent = shape.indent.block_indent(context.config);
1544 let nested_shape = Shape::indented(nested_indent, context.config);
1545 let pre_comment = rewrite_missing_comment(pre_span, nested_shape, context)?;
1546 let post_comment = rewrite_missing_comment(post_span, nested_shape, context)?;
1547 let subexpr_str = subexpr.rewrite_result(context, nested_shape)?;
1548
1549 let mut result = String::with_capacity(subexpr_str.len() * 2);
1550 result.push('(');
1551 if !pre_comment.is_empty() {
1552 result.push_str(&nested_indent.to_string_with_newline(context.config));
1553 result.push_str(&pre_comment);
1554 }
1555 result.push_str(&nested_indent.to_string_with_newline(context.config));
1556 result.push_str(&subexpr_str);
1557 if !post_comment.is_empty() {
1558 result.push_str(&nested_indent.to_string_with_newline(context.config));
1559 result.push_str(&post_comment);
1560 }
1561 result.push_str(&shape.indent.to_string_with_newline(context.config));
1562 result.push(')');
1563
1564 Ok(result)
1565}
1566
1567fn rewrite_index(
1568 expr: &ast::Expr,
1569 index: &ast::Expr,
1570 context: &RewriteContext<'_>,
1571 shape: Shape,
1572) -> RewriteResult {
1573 let expr_str = expr.rewrite_result(context, shape)?;
1574
1575 let offset = last_line_width(&expr_str) + 1;
1576 let rhs_overhead = shape.rhs_overhead(context.config);
1577 let index_shape = if expr_str.contains('\n') {
1578 Shape::legacy(context.config.max_width(), shape.indent)
1579 .offset_left(offset)
1580 .and_then(|shape| shape.sub_width(1 + rhs_overhead))
1581 } else {
1582 match context.config.indent_style() {
1583 IndentStyle::Block => shape
1584 .offset_left(offset)
1585 .and_then(|shape| shape.sub_width(1)),
1586 IndentStyle::Visual => shape.visual_indent(offset).sub_width(offset + 1),
1587 }
1588 }
1589 .max_width_error(shape.width, index.span());
1590 let orig_index_rw = index_shape.and_then(|s| index.rewrite_result(context, s));
1591
1592 match orig_index_rw {
1594 Ok(ref index_str) if !index_str.contains('\n') => {
1595 return Ok(format!("{expr_str}[{index_str}]"));
1596 }
1597 _ => (),
1598 }
1599
1600 let indent = shape.indent.block_indent(context.config);
1602 let index_shape = Shape::indented(indent, context.config)
1603 .offset_left(1)
1604 .max_width_error(shape.width, index.span())?;
1605 let index_shape = index_shape
1606 .sub_width(1 + rhs_overhead)
1607 .max_width_error(index_shape.width, index.span())?;
1608 let new_index_rw = index.rewrite_result(context, index_shape);
1609 match (orig_index_rw, new_index_rw) {
1610 (_, Ok(ref new_index_str)) if !new_index_str.contains('\n') => Ok(format!(
1611 "{}{}[{}]",
1612 expr_str,
1613 indent.to_string_with_newline(context.config),
1614 new_index_str,
1615 )),
1616 (Err(_), Ok(ref new_index_str)) => Ok(format!(
1617 "{}{}[{}]",
1618 expr_str,
1619 indent.to_string_with_newline(context.config),
1620 new_index_str,
1621 )),
1622 (Ok(ref index_str), _) => Ok(format!("{expr_str}[{index_str}]")),
1623 (Err(_), Err(new_index_rw_err)) => Err(new_index_rw_err),
1627 }
1628}
1629
1630fn struct_lit_can_be_aligned(fields: &[ast::ExprField], has_base: bool) -> bool {
1631 !has_base && fields.iter().all(|field| !field.is_shorthand)
1632}
1633
1634fn rewrite_struct_lit<'a>(
1635 context: &RewriteContext<'_>,
1636 path: &ast::Path,
1637 qself: &Option<ptr::P<ast::QSelf>>,
1638 fields: &'a [ast::ExprField],
1639 struct_rest: &ast::StructRest,
1640 attrs: &[ast::Attribute],
1641 span: Span,
1642 shape: Shape,
1643) -> RewriteResult {
1644 debug!("rewrite_struct_lit: shape {:?}", shape);
1645
1646 enum StructLitField<'a> {
1647 Regular(&'a ast::ExprField),
1648 Base(&'a ast::Expr),
1649 Rest(Span),
1650 }
1651
1652 let path_shape = shape.sub_width(2).max_width_error(shape.width, span)?;
1654 let path_str = rewrite_path(context, PathContext::Expr, qself, path, path_shape)?;
1655
1656 let has_base_or_rest = match struct_rest {
1657 ast::StructRest::None if fields.is_empty() => return Ok(format!("{path_str} {{}}")),
1658 ast::StructRest::Rest(_) if fields.is_empty() => {
1659 return Ok(format!("{path_str} {{ .. }}"));
1660 }
1661 ast::StructRest::Rest(_) | ast::StructRest::Base(_) => true,
1662 _ => false,
1663 };
1664
1665 let (h_shape, v_shape) = struct_lit_shape(shape, context, path_str.len() + 3, 2)
1667 .max_width_error(shape.width, span)?;
1668
1669 let one_line_width = h_shape.map_or(0, |shape| shape.width);
1670 let body_lo = context.snippet_provider.span_after(span, "{");
1671 let fields_str = if struct_lit_can_be_aligned(fields, has_base_or_rest)
1672 && context.config.struct_field_align_threshold() > 0
1673 {
1674 rewrite_with_alignment(
1675 fields,
1676 context,
1677 v_shape,
1678 mk_sp(body_lo, span.hi()),
1679 one_line_width,
1680 )
1681 .unknown_error()?
1682 } else {
1683 let field_iter = fields.iter().map(StructLitField::Regular).chain(
1684 match struct_rest {
1685 ast::StructRest::Base(expr) => Some(StructLitField::Base(&**expr)),
1686 ast::StructRest::Rest(span) => Some(StructLitField::Rest(*span)),
1687 ast::StructRest::None => None,
1688 }
1689 .into_iter(),
1690 );
1691
1692 let span_lo = |item: &StructLitField<'_>| match *item {
1693 StructLitField::Regular(field) => field.span().lo(),
1694 StructLitField::Base(expr) => {
1695 let last_field_hi = fields.last().map_or(span.lo(), |field| field.span.hi());
1696 let snippet = context.snippet(mk_sp(last_field_hi, expr.span.lo()));
1697 let pos = snippet.find_uncommented("..").unwrap();
1698 last_field_hi + BytePos(pos as u32)
1699 }
1700 StructLitField::Rest(span) => span.lo(),
1701 };
1702 let span_hi = |item: &StructLitField<'_>| match *item {
1703 StructLitField::Regular(field) => field.span().hi(),
1704 StructLitField::Base(expr) => expr.span.hi(),
1705 StructLitField::Rest(span) => span.hi(),
1706 };
1707 let rewrite = |item: &StructLitField<'_>| match *item {
1708 StructLitField::Regular(field) => {
1709 rewrite_field(
1711 context,
1712 field,
1713 v_shape.sub_width(1).max_width_error(v_shape.width, span)?,
1714 0,
1715 )
1716 }
1717 StructLitField::Base(expr) => {
1718 expr.rewrite_result(
1720 context,
1721 v_shape
1722 .offset_left(2)
1723 .max_width_error(v_shape.width, span)?,
1724 )
1725 .map(|s| format!("..{}", s))
1726 }
1727 StructLitField::Rest(_) => Ok("..".to_owned()),
1728 };
1729
1730 let items = itemize_list(
1731 context.snippet_provider,
1732 field_iter,
1733 "}",
1734 ",",
1735 span_lo,
1736 span_hi,
1737 rewrite,
1738 body_lo,
1739 span.hi(),
1740 false,
1741 );
1742 let item_vec = items.collect::<Vec<_>>();
1743
1744 let tactic = struct_lit_tactic(h_shape, context, &item_vec);
1745 let nested_shape = shape_for_tactic(tactic, h_shape, v_shape);
1746
1747 let ends_with_comma = span_ends_with_comma(context, span);
1748 let force_no_trailing_comma = context.inside_macro() && !ends_with_comma;
1749
1750 let fmt = struct_lit_formatting(
1751 nested_shape,
1752 tactic,
1753 context,
1754 force_no_trailing_comma || has_base_or_rest || !context.use_block_indent(),
1755 );
1756
1757 write_list(&item_vec, &fmt)?
1758 };
1759
1760 let fields_str =
1761 wrap_struct_field(context, attrs, &fields_str, shape, v_shape, one_line_width)?;
1762 Ok(format!("{path_str} {{{fields_str}}}"))
1763
1764 }
1767
1768pub(crate) fn wrap_struct_field(
1769 context: &RewriteContext<'_>,
1770 attrs: &[ast::Attribute],
1771 fields_str: &str,
1772 shape: Shape,
1773 nested_shape: Shape,
1774 one_line_width: usize,
1775) -> RewriteResult {
1776 let should_vertical = context.config.indent_style() == IndentStyle::Block
1777 && (fields_str.contains('\n')
1778 || !context.config.struct_lit_single_line()
1779 || fields_str.len() > one_line_width);
1780
1781 let inner_attrs = &inner_attributes(attrs);
1782 if inner_attrs.is_empty() {
1783 if should_vertical {
1784 Ok(format!(
1785 "{}{}{}",
1786 nested_shape.indent.to_string_with_newline(context.config),
1787 fields_str,
1788 shape.indent.to_string_with_newline(context.config)
1789 ))
1790 } else {
1791 Ok(format!(" {fields_str} "))
1793 }
1794 } else {
1795 Ok(format!(
1796 "{}{}{}{}{}",
1797 nested_shape.indent.to_string_with_newline(context.config),
1798 inner_attrs.rewrite_result(context, shape)?,
1799 nested_shape.indent.to_string_with_newline(context.config),
1800 fields_str,
1801 shape.indent.to_string_with_newline(context.config)
1802 ))
1803 }
1804}
1805
1806pub(crate) fn struct_lit_field_separator(config: &Config) -> &str {
1807 colon_spaces(config)
1808}
1809
1810pub(crate) fn rewrite_field(
1811 context: &RewriteContext<'_>,
1812 field: &ast::ExprField,
1813 shape: Shape,
1814 prefix_max_width: usize,
1815) -> RewriteResult {
1816 if contains_skip(&field.attrs) {
1817 return Ok(context.snippet(field.span()).to_owned());
1818 }
1819 let mut attrs_str = field.attrs.rewrite_result(context, shape)?;
1820 if !attrs_str.is_empty() {
1821 attrs_str.push_str(&shape.indent.to_string_with_newline(context.config));
1822 };
1823 let name = context.snippet(field.ident.span);
1824 if field.is_shorthand {
1825 Ok(attrs_str + name)
1826 } else {
1827 let mut separator = String::from(struct_lit_field_separator(context.config));
1828 for _ in 0..prefix_max_width.saturating_sub(name.len()) {
1829 separator.push(' ');
1830 }
1831 let overhead = name.len() + separator.len();
1832 let expr_shape = shape
1833 .offset_left(overhead)
1834 .max_width_error(shape.width, field.span)?;
1835 let expr = field.expr.rewrite_result(context, expr_shape);
1836 let is_lit = matches!(field.expr.kind, ast::ExprKind::Lit(_));
1837 match expr {
1838 Ok(ref e)
1839 if !is_lit && e.as_str() == name && context.config.use_field_init_shorthand() =>
1840 {
1841 Ok(attrs_str + name)
1842 }
1843 Ok(e) => Ok(format!("{attrs_str}{name}{separator}{e}")),
1844 Err(_) => {
1845 let expr_offset = shape.indent.block_indent(context.config);
1846 let expr = field
1847 .expr
1848 .rewrite_result(context, Shape::indented(expr_offset, context.config));
1849 expr.map(|s| {
1850 format!(
1851 "{}{}:\n{}{}",
1852 attrs_str,
1853 name,
1854 expr_offset.to_string(context.config),
1855 s
1856 )
1857 })
1858 }
1859 }
1860 }
1861}
1862
1863fn rewrite_tuple_in_visual_indent_style<'a, T: 'a + IntoOverflowableItem<'a>>(
1864 context: &RewriteContext<'_>,
1865 mut items: impl Iterator<Item = &'a T>,
1866 span: Span,
1867 shape: Shape,
1868 is_singleton_tuple: bool,
1869) -> RewriteResult {
1870 debug!("rewrite_tuple_in_visual_indent_style {:?}", shape);
1872 if is_singleton_tuple {
1873 let nested_shape = shape
1875 .sub_width(3)
1876 .max_width_error(shape.width, span)?
1877 .visual_indent(1);
1878 return items
1879 .next()
1880 .unwrap()
1881 .rewrite_result(context, nested_shape)
1882 .map(|s| format!("({},)", s));
1883 }
1884
1885 let list_lo = context.snippet_provider.span_after(span, "(");
1886 let nested_shape = shape
1887 .sub_width(2)
1888 .max_width_error(shape.width, span)?
1889 .visual_indent(1);
1890 let items = itemize_list(
1891 context.snippet_provider,
1892 items,
1893 ")",
1894 ",",
1895 |item| item.span().lo(),
1896 |item| item.span().hi(),
1897 |item| item.rewrite_result(context, nested_shape),
1898 list_lo,
1899 span.hi() - BytePos(1),
1900 false,
1901 );
1902 let item_vec: Vec<_> = items.collect();
1903 let tactic = definitive_tactic(
1904 &item_vec,
1905 ListTactic::HorizontalVertical,
1906 Separator::Comma,
1907 nested_shape.width,
1908 );
1909 let fmt = ListFormatting::new(nested_shape, context.config)
1910 .tactic(tactic)
1911 .ends_with_newline(false);
1912 let list_str = write_list(&item_vec, &fmt)?;
1913
1914 Ok(format!("({list_str})"))
1915}
1916
1917fn rewrite_let(
1918 context: &RewriteContext<'_>,
1919 shape: Shape,
1920 pat: &ast::Pat,
1921 expr: &ast::Expr,
1922) -> RewriteResult {
1923 let mut result = "let ".to_owned();
1924
1925 let pat_shape = shape
1929 .offset_left(4)
1930 .max_width_error(shape.width, pat.span)?;
1931 let pat_str = pat.rewrite_result(context, pat_shape)?;
1932 result.push_str(&pat_str);
1933
1934 result.push_str(" =");
1936
1937 let comments_lo = context
1938 .snippet_provider
1939 .span_after(expr.span.with_lo(pat.span.hi()), "=");
1940 let comments_span = mk_sp(comments_lo, expr.span.lo());
1941 rewrite_assign_rhs_with_comments(
1942 context,
1943 result,
1944 expr,
1945 shape,
1946 &RhsAssignKind::Expr(&expr.kind, expr.span),
1947 RhsTactics::Default,
1948 comments_span,
1949 true,
1950 )
1951}
1952
1953pub(crate) fn rewrite_tuple<'a, T: 'a + IntoOverflowableItem<'a>>(
1954 context: &'a RewriteContext<'_>,
1955 items: impl Iterator<Item = &'a T>,
1956 span: Span,
1957 shape: Shape,
1958 is_singleton_tuple: bool,
1959) -> RewriteResult {
1960 debug!("rewrite_tuple {:?}", shape);
1961 if context.use_block_indent() {
1962 let force_tactic = if context.inside_macro() {
1964 if span_ends_with_comma(context, span) {
1965 Some(SeparatorTactic::Always)
1966 } else {
1967 Some(SeparatorTactic::Never)
1968 }
1969 } else if is_singleton_tuple {
1970 Some(SeparatorTactic::Always)
1971 } else {
1972 None
1973 };
1974 overflow::rewrite_with_parens(
1975 context,
1976 "",
1977 items,
1978 shape,
1979 span,
1980 context.config.fn_call_width(),
1981 force_tactic,
1982 )
1983 } else {
1984 rewrite_tuple_in_visual_indent_style(context, items, span, shape, is_singleton_tuple)
1985 }
1986}
1987
1988pub(crate) fn rewrite_unary_prefix<R: Rewrite + Spanned>(
1989 context: &RewriteContext<'_>,
1990 prefix: &str,
1991 rewrite: &R,
1992 shape: Shape,
1993) -> RewriteResult {
1994 let shape = shape
1995 .offset_left(prefix.len())
1996 .max_width_error(shape.width, rewrite.span())?;
1997 rewrite
1998 .rewrite_result(context, shape)
1999 .map(|r| format!("{}{}", prefix, r))
2000}
2001
2002pub(crate) fn rewrite_unary_suffix<R: Rewrite + Spanned>(
2005 context: &RewriteContext<'_>,
2006 suffix: &str,
2007 rewrite: &R,
2008 shape: Shape,
2009) -> RewriteResult {
2010 let shape = shape
2011 .sub_width(suffix.len())
2012 .max_width_error(shape.width, rewrite.span())?;
2013 rewrite.rewrite_result(context, shape).map(|mut r| {
2014 r.push_str(suffix);
2015 r
2016 })
2017}
2018
2019fn rewrite_unary_op(
2020 context: &RewriteContext<'_>,
2021 op: ast::UnOp,
2022 expr: &ast::Expr,
2023 shape: Shape,
2024) -> RewriteResult {
2025 rewrite_unary_prefix(context, op.as_str(), expr, shape)
2027}
2028
2029pub(crate) enum RhsAssignKind<'ast> {
2030 Expr(&'ast ast::ExprKind, #[allow(dead_code)] Span),
2031 Bounds,
2032 Ty,
2033}
2034
2035impl<'ast> RhsAssignKind<'ast> {
2036 #[allow(dead_code)]
2041 fn is_chain(&self) -> bool {
2042 match self {
2043 RhsAssignKind::Expr(kind, _) => {
2044 matches!(
2045 kind,
2046 ast::ExprKind::Try(..)
2047 | ast::ExprKind::Field(..)
2048 | ast::ExprKind::MethodCall(..)
2049 | ast::ExprKind::Await(_, _)
2050 )
2051 }
2052 _ => false,
2053 }
2054 }
2055}
2056
2057fn rewrite_assignment(
2058 context: &RewriteContext<'_>,
2059 lhs: &ast::Expr,
2060 rhs: &ast::Expr,
2061 op: Option<&ast::BinOp>,
2062 shape: Shape,
2063) -> RewriteResult {
2064 let operator_str = match op {
2065 Some(op) => context.snippet(op.span),
2066 None => "=",
2067 };
2068
2069 let lhs_shape = shape
2071 .sub_width(operator_str.len() + 1)
2072 .max_width_error(shape.width, lhs.span())?;
2073 let lhs_str = format!(
2074 "{} {}",
2075 lhs.rewrite_result(context, lhs_shape)?,
2076 operator_str
2077 );
2078
2079 rewrite_assign_rhs(
2080 context,
2081 lhs_str,
2082 rhs,
2083 &RhsAssignKind::Expr(&rhs.kind, rhs.span),
2084 shape,
2085 )
2086}
2087
2088#[derive(Debug, Copy, Clone, PartialEq, Eq)]
2090pub(crate) enum RhsTactics {
2091 Default,
2093 ForceNextLineWithoutIndent,
2095 AllowOverflow,
2098}
2099
2100pub(crate) fn rewrite_assign_rhs<S: Into<String>, R: Rewrite>(
2103 context: &RewriteContext<'_>,
2104 lhs: S,
2105 ex: &R,
2106 rhs_kind: &RhsAssignKind<'_>,
2107 shape: Shape,
2108) -> RewriteResult {
2109 rewrite_assign_rhs_with(context, lhs, ex, shape, rhs_kind, RhsTactics::Default)
2110}
2111
2112pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
2113 context: &RewriteContext<'_>,
2114 lhs: &str,
2115 ex: &R,
2116 shape: Shape,
2117 rhs_kind: &RhsAssignKind<'_>,
2118 rhs_tactics: RhsTactics,
2119) -> RewriteResult {
2120 let last_line_width = last_line_width(lhs).saturating_sub(if lhs.contains('\n') {
2121 shape.indent.width()
2122 } else {
2123 0
2124 });
2125 let orig_shape = shape.offset_left(last_line_width + 1).unwrap_or(Shape {
2127 width: 0,
2128 offset: shape.offset + last_line_width + 1,
2129 ..shape
2130 });
2131 let has_rhs_comment = if let Some(offset) = lhs.find_last_uncommented("=") {
2132 lhs.trim_end().len() > offset + 1
2133 } else {
2134 false
2135 };
2136
2137 choose_rhs(
2138 context,
2139 ex,
2140 orig_shape,
2141 ex.rewrite_result(context, orig_shape),
2142 rhs_kind,
2143 rhs_tactics,
2144 has_rhs_comment,
2145 )
2146}
2147
2148pub(crate) fn rewrite_assign_rhs_with<S: Into<String>, R: Rewrite>(
2149 context: &RewriteContext<'_>,
2150 lhs: S,
2151 ex: &R,
2152 shape: Shape,
2153 rhs_kind: &RhsAssignKind<'_>,
2154 rhs_tactics: RhsTactics,
2155) -> RewriteResult {
2156 let lhs = lhs.into();
2157 let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
2158 Ok(lhs + &rhs)
2159}
2160
2161pub(crate) fn rewrite_assign_rhs_with_comments<S: Into<String>, R: Rewrite + Spanned>(
2162 context: &RewriteContext<'_>,
2163 lhs: S,
2164 ex: &R,
2165 shape: Shape,
2166 rhs_kind: &RhsAssignKind<'_>,
2167 rhs_tactics: RhsTactics,
2168 between_span: Span,
2169 allow_extend: bool,
2170) -> RewriteResult {
2171 let lhs = lhs.into();
2172 let contains_comment = contains_comment(context.snippet(between_span));
2173 let shape = if contains_comment {
2174 shape
2175 .block_left(context.config.tab_spaces())
2176 .max_width_error(shape.width, between_span.with_hi(ex.span().hi()))?
2177 } else {
2178 shape
2179 };
2180 let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
2181 if contains_comment {
2182 let rhs = rhs.trim_start();
2183 combine_strs_with_missing_comments(context, &lhs, rhs, between_span, shape, allow_extend)
2184 } else {
2185 Ok(lhs + &rhs)
2186 }
2187}
2188
2189fn choose_rhs<R: Rewrite>(
2190 context: &RewriteContext<'_>,
2191 expr: &R,
2192 shape: Shape,
2193 orig_rhs: RewriteResult,
2194 _rhs_kind: &RhsAssignKind<'_>,
2195 rhs_tactics: RhsTactics,
2196 has_rhs_comment: bool,
2197) -> RewriteResult {
2198 match orig_rhs {
2199 Ok(ref new_str) if new_str.is_empty() => Ok(String::new()),
2200 Ok(ref new_str) if !new_str.contains('\n') && unicode_str_width(new_str) <= shape.width => {
2201 Ok(format!(" {new_str}"))
2202 }
2203 _ => {
2204 let new_shape = shape_from_rhs_tactic(context, shape, rhs_tactics)
2207 .unknown_error()?;
2211 let new_rhs = expr.rewrite_result(context, new_shape);
2212 let new_indent_str = &shape
2213 .indent
2214 .block_indent(context.config)
2215 .to_string_with_newline(context.config);
2216 let before_space_str = if has_rhs_comment { "" } else { " " };
2217
2218 match (orig_rhs, new_rhs) {
2219 (Ok(ref orig_rhs), Ok(ref new_rhs))
2220 if !filtered_str_fits(&new_rhs, context.config.max_width(), new_shape) =>
2221 {
2222 Ok(format!("{before_space_str}{orig_rhs}"))
2223 }
2224 (Ok(ref orig_rhs), Ok(ref new_rhs))
2225 if prefer_next_line(orig_rhs, new_rhs, rhs_tactics) =>
2226 {
2227 Ok(format!("{new_indent_str}{new_rhs}"))
2228 }
2229 (Err(_), Ok(ref new_rhs)) => Ok(format!("{new_indent_str}{new_rhs}")),
2230 (Err(_), Err(_)) if rhs_tactics == RhsTactics::AllowOverflow => {
2231 let shape = shape.infinite_width();
2232 expr.rewrite_result(context, shape)
2233 .map(|s| format!("{}{}", before_space_str, s))
2234 }
2235 (Err(_), Err(new_rhs_err)) => Err(new_rhs_err),
2239 (Ok(orig_rhs), _) => Ok(format!("{before_space_str}{orig_rhs}")),
2240 }
2241 }
2242 }
2243}
2244
2245fn shape_from_rhs_tactic(
2246 context: &RewriteContext<'_>,
2247 shape: Shape,
2248 rhs_tactic: RhsTactics,
2249) -> Option<Shape> {
2250 match rhs_tactic {
2251 RhsTactics::ForceNextLineWithoutIndent => shape
2252 .with_max_width(context.config)
2253 .sub_width(shape.indent.width()),
2254 RhsTactics::Default | RhsTactics::AllowOverflow => {
2255 Shape::indented(shape.indent.block_indent(context.config), context.config)
2256 .sub_width(shape.rhs_overhead(context.config))
2257 }
2258 }
2259}
2260
2261pub(crate) fn prefer_next_line(
2271 orig_rhs: &str,
2272 next_line_rhs: &str,
2273 rhs_tactics: RhsTactics,
2274) -> bool {
2275 rhs_tactics == RhsTactics::ForceNextLineWithoutIndent
2276 || !next_line_rhs.contains('\n')
2277 || count_newlines(orig_rhs) > count_newlines(next_line_rhs) + 1
2278 || first_line_ends_with(orig_rhs, '(') && !first_line_ends_with(next_line_rhs, '(')
2279 || first_line_ends_with(orig_rhs, '{') && !first_line_ends_with(next_line_rhs, '{')
2280 || first_line_ends_with(orig_rhs, '[') && !first_line_ends_with(next_line_rhs, '[')
2281}
2282
2283fn rewrite_expr_addrof(
2284 context: &RewriteContext<'_>,
2285 borrow_kind: ast::BorrowKind,
2286 mutability: ast::Mutability,
2287 expr: &ast::Expr,
2288 shape: Shape,
2289) -> RewriteResult {
2290 let operator_str = match (mutability, borrow_kind) {
2291 (ast::Mutability::Not, ast::BorrowKind::Ref) => "&",
2292 (ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ",
2293 (ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ",
2294 (ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ",
2295 };
2296 rewrite_unary_prefix(context, operator_str, expr, shape)
2297}
2298
2299pub(crate) fn is_method_call(expr: &ast::Expr) -> bool {
2300 match expr.kind {
2301 ast::ExprKind::MethodCall(..) => true,
2302 ast::ExprKind::AddrOf(_, _, ref expr)
2303 | ast::ExprKind::Cast(ref expr, _)
2304 | ast::ExprKind::Try(ref expr)
2305 | ast::ExprKind::Unary(_, ref expr) => is_method_call(expr),
2306 _ => false,
2307 }
2308}
2309
2310#[cfg(test)]
2311mod test {
2312 use super::last_line_offsetted;
2313
2314 #[test]
2315 fn test_last_line_offsetted() {
2316 let lines = "one\n two";
2317 assert_eq!(last_line_offsetted(2, lines), true);
2318 assert_eq!(last_line_offsetted(4, lines), false);
2319 assert_eq!(last_line_offsetted(6, lines), false);
2320
2321 let lines = "one two";
2322 assert_eq!(last_line_offsetted(2, lines), false);
2323 assert_eq!(last_line_offsetted(0, lines), false);
2324
2325 let lines = "\ntwo";
2326 assert_eq!(last_line_offsetted(2, lines), false);
2327 assert_eq!(last_line_offsetted(0, lines), false);
2328
2329 let lines = "one\n two three";
2330 assert_eq!(last_line_offsetted(2, lines), true);
2331 let lines = "one\n two three";
2332 assert_eq!(last_line_offsetted(2, lines), false);
2333 }
2334}