• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> {
span(&self) -> Span19     fn span(&self) -> Span {
20         self.inner.span()
21     }
22 }
23 
24 impl<'a> Stmt<'a> {
as_ast_node(&self) -> &ast::Stmt25     pub(crate) fn as_ast_node(&self) -> &ast::Stmt {
26         self.inner
27     }
28 
to_item(&self) -> Option<&ast::Item>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 
from_ast_node(inner: &'a ast::Stmt, is_last: bool) -> Self36     pub(crate) fn from_ast_node(inner: &'a ast::Stmt, is_last: bool) -> Self {
37         Stmt { inner, is_last }
38     }
39 
from_ast_nodes<I>(iter: I) -> Vec<Self> where I: Iterator<Item = &'a ast::Stmt>,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 
is_empty(&self) -> bool55     pub(crate) fn is_empty(&self) -> bool {
56         matches!(self.inner.kind, ast::StmtKind::Empty)
57     }
58 
is_last_expr(&self) -> bool59     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> {
rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>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 {
rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>88     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
89         format_stmt(context, shape, self, ExprType::Statement)
90     }
91 }
92 
format_stmt( context: &RewriteContext<'_>, shape: Shape, stmt: &ast::Stmt, expr_type: ExprType, ) -> Option<String>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 }
117