]> git.proxmox.com Git - rustc.git/blob - src/tools/rustfmt/src/stmt.rs
New upstream version 1.63.0+dfsg1
[rustc.git] / src / tools / rustfmt / src / stmt.rs
1 use rustc_ast::ast;
2 use rustc_span::Span;
3
4 use crate::comment::recover_comment_removed;
5 use crate::config::Version;
6 use crate::expr::{format_expr, ExprType};
7 use crate::rewrite::{Rewrite, RewriteContext};
8 use crate::shape::Shape;
9 use crate::source_map::LineRangeUtils;
10 use crate::spanned::Spanned;
11 use crate::utils::semicolon_for_stmt;
12
13 pub(crate) struct Stmt<'a> {
14 inner: &'a ast::Stmt,
15 is_last: bool,
16 }
17
18 impl<'a> Spanned for Stmt<'a> {
19 fn span(&self) -> Span {
20 self.inner.span()
21 }
22 }
23
24 impl<'a> Stmt<'a> {
25 pub(crate) fn as_ast_node(&self) -> &ast::Stmt {
26 self.inner
27 }
28
29 pub(crate) fn to_item(&self) -> Option<&ast::Item> {
30 match self.inner.kind {
31 ast::StmtKind::Item(ref item) => Some(&**item),
32 _ => None,
33 }
34 }
35
36 pub(crate) fn from_ast_node(inner: &'a ast::Stmt, is_last: bool) -> Self {
37 Stmt { inner, is_last }
38 }
39
40 pub(crate) fn from_ast_nodes<I>(iter: I) -> Vec<Self>
41 where
42 I: Iterator<Item = &'a ast::Stmt>,
43 {
44 let mut result = vec![];
45 let mut iter = iter.peekable();
46 while iter.peek().is_some() {
47 result.push(Stmt {
48 inner: iter.next().unwrap(),
49 is_last: iter.peek().is_none(),
50 })
51 }
52 result
53 }
54
55 pub(crate) fn is_empty(&self) -> bool {
56 matches!(self.inner.kind, ast::StmtKind::Empty)
57 }
58
59 fn is_last_expr(&self) -> bool {
60 if !self.is_last {
61 return false;
62 }
63
64 match self.as_ast_node().kind {
65 ast::StmtKind::Expr(ref expr) => match expr.kind {
66 ast::ExprKind::Ret(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Break(..) => {
67 false
68 }
69 _ => true,
70 },
71 _ => false,
72 }
73 }
74 }
75
76 impl<'a> Rewrite for Stmt<'a> {
77 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
78 let expr_type = if context.config.version() == Version::Two && self.is_last_expr() {
79 ExprType::SubExpression
80 } else {
81 ExprType::Statement
82 };
83 format_stmt(context, shape, self.as_ast_node(), expr_type)
84 }
85 }
86
87 impl Rewrite for ast::Stmt {
88 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
89 format_stmt(context, shape, self, ExprType::Statement)
90 }
91 }
92
93 fn format_stmt(
94 context: &RewriteContext<'_>,
95 shape: Shape,
96 stmt: &ast::Stmt,
97 expr_type: ExprType,
98 ) -> Option<String> {
99 skip_out_of_file_lines_range!(context, stmt.span());
100
101 let result = match stmt.kind {
102 ast::StmtKind::Local(ref local) => local.rewrite(context, shape),
103 ast::StmtKind::Expr(ref ex) | ast::StmtKind::Semi(ref ex) => {
104 let suffix = if semicolon_for_stmt(context, stmt) {
105 ";"
106 } else {
107 ""
108 };
109
110 let shape = shape.sub_width(suffix.len())?;
111 format_expr(ex, expr_type, context, shape).map(|s| s + suffix)
112 }
113 ast::StmtKind::MacCall(..) | ast::StmtKind::Item(..) | ast::StmtKind::Empty => None,
114 };
115 result.and_then(|res| recover_comment_removed(res, stmt.span(), context))
116 }