1 use std::cell::{Cell, RefCell};
4 use rustc_ast::token::DelimToken;
5 use rustc_ast::{ast, visit};
6 use rustc_span::{BytePos, Pos, Span};
9 use crate::comment::{rewrite_comment, CodeCharKind, CommentCodeSlices};
10 use crate::config::Version;
11 use crate::config::{BraceStyle, Config};
12 use crate::coverage::transform_missing_snippet;
14 format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item,
15 rewrite_associated_impl_type, rewrite_associated_type, rewrite_extern_crate,
16 rewrite_opaque_impl_type, rewrite_opaque_type, rewrite_type_alias, FnBraceStyle, FnSig,
17 StaticParts, StructParts,
19 use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition};
20 use crate::rewrite::{Rewrite, RewriteContext};
21 use crate::shape::{Indent, Shape};
22 use crate::skip::{is_skip_attr, SkipContext};
23 use crate::source_map::{LineRangeUtils, SpanUtils};
24 use crate::spanned::Spanned;
25 use crate::stmt::Stmt;
26 use crate::syntux::session::ParseSess;
28 self, contains_skip, count_newlines, depr_skip_annotation, inner_attributes, last_line_width,
29 mk_sp, ptr_vec_to_ref_vec, rewrite_ident, stmt_expr,
31 use crate::{ErrorKind, FormatReport, FormattingError};
33 /// Creates a string slice corresponding to the specified span.
34 pub(crate) struct SnippetProvider {
35 /// A pointer to the content of the file we are formatting.
36 big_snippet: Rc<String>,
37 /// A position of the start of `big_snippet`, used as an offset.
39 /// A end position of the file that this snippet lives.
43 impl SnippetProvider {
44 pub(crate) fn span_to_snippet(&self, span: Span) -> Option<&str> {
45 let start_index = span.lo().to_usize().checked_sub(self.start_pos)?;
46 let end_index = span.hi().to_usize().checked_sub(self.start_pos)?;
47 Some(&self.big_snippet[start_index..end_index])
50 pub(crate) fn new(start_pos: BytePos, end_pos: BytePos, big_snippet: Rc<String>) -> Self {
51 let start_pos = start_pos.to_usize();
52 let end_pos = end_pos.to_usize();
60 pub(crate) fn entire_snippet(&self) -> &str {
61 self.big_snippet.as_str()
64 pub(crate) fn start_pos(&self) -> BytePos {
65 BytePos::from_usize(self.start_pos)
68 pub(crate) fn end_pos(&self) -> BytePos {
69 BytePos::from_usize(self.end_pos)
73 pub(crate) struct FmtVisitor<'a> {
74 parent_context: Option<&'a RewriteContext<'a>>,
75 pub(crate) parse_sess: &'a ParseSess,
76 pub(crate) buffer: String,
77 pub(crate) last_pos: BytePos,
78 // FIXME: use an RAII util or closure for indenting
79 pub(crate) block_indent: Indent,
80 pub(crate) config: &'a Config,
81 pub(crate) is_if_else_block: bool,
82 pub(crate) snippet_provider: &'a SnippetProvider,
83 pub(crate) line_number: usize,
84 /// List of 1-based line ranges which were annotated with skip
85 /// Both bounds are inclusifs.
86 pub(crate) skipped_range: Rc<RefCell<Vec<(usize, usize)>>>,
87 pub(crate) macro_rewrite_failure: bool,
88 pub(crate) report: FormatReport,
89 pub(crate) skip_context: SkipContext,
92 impl<'a> Drop for FmtVisitor<'a> {
94 if let Some(ctx) = self.parent_context {
95 if self.macro_rewrite_failure {
96 ctx.macro_rewrite_failure.replace(true);
102 impl<'b, 'a: 'b> FmtVisitor<'a> {
103 fn set_parent_context(&mut self, context: &'a RewriteContext<'_>) {
104 self.parent_context = Some(context);
107 pub(crate) fn shape(&self) -> Shape {
108 Shape::indented(self.block_indent, self.config)
111 fn next_span(&self, hi: BytePos) -> Span {
112 mk_sp(self.last_pos, hi)
115 fn visit_stmt(&mut self, stmt: &Stmt<'_>) {
118 self.parse_sess.span_to_debug_info(stmt.span())
121 // https://github.com/rust-lang/rust/issues/63679.
122 let is_all_semicolons =
123 |snippet: &str| snippet.chars().all(|c| c.is_whitespace() || c == ';');
124 if is_all_semicolons(&self.snippet(stmt.span())) {
125 self.last_pos = stmt.span().hi();
129 match stmt.as_ast_node().kind {
130 ast::StmtKind::Item(ref item) => {
131 self.visit_item(item);
132 // Handle potential `;` after the item.
133 self.format_missing(stmt.span().hi());
135 ast::StmtKind::Local(..) | ast::StmtKind::Expr(..) | ast::StmtKind::Semi(..) => {
136 let attrs = get_attrs_from_stmt(stmt.as_ast_node());
137 if contains_skip(attrs) {
138 self.push_skipped_with_span(
141 get_span_without_attrs(stmt.as_ast_node()),
144 let shape = self.shape();
145 let rewrite = self.with_context(|ctx| stmt.rewrite(&ctx, shape));
146 self.push_rewrite(stmt.span(), rewrite)
149 ast::StmtKind::MacCall(ref mac) => {
150 let (ref mac, _macro_style, ref attrs) = **mac;
151 if self.visit_attrs(attrs, ast::AttrStyle::Outer) {
152 self.push_skipped_with_span(
155 get_span_without_attrs(stmt.as_ast_node()),
158 self.visit_mac(mac, None, MacroPosition::Statement);
160 self.format_missing(stmt.span().hi());
162 ast::StmtKind::Empty => (),
166 /// Remove spaces between the opening brace and the first statement or the inner attribute
168 fn trim_spaces_after_opening_brace(
171 inner_attrs: Option<&[ast::Attribute]>,
173 if let Some(first_stmt) = b.stmts.first() {
175 .and_then(|attrs| inner_attributes(attrs).first().map(|attr| attr.span.lo()))
176 .unwrap_or_else(|| first_stmt.span().lo());
177 let missing_span = self.next_span(hi);
178 let snippet = self.snippet(missing_span);
179 let len = CommentCodeSlices::new(snippet)
181 .and_then(|(kind, _, s)| {
182 if kind == CodeCharKind::Normal {
188 if let Some(len) = len {
189 self.last_pos = self.last_pos + BytePos::from_usize(len);
194 pub(crate) fn visit_block(
197 inner_attrs: Option<&[ast::Attribute]>,
202 self.parse_sess.span_to_debug_info(b.span),
205 // Check if this block has braces.
206 let brace_compensation = BytePos(if has_braces { 1 } else { 0 });
208 self.last_pos = self.last_pos + brace_compensation;
209 self.block_indent = self.block_indent.block_indent(self.config);
211 self.trim_spaces_after_opening_brace(b, inner_attrs);
213 // Format inner attributes if available.
214 if let Some(attrs) = inner_attrs {
215 self.visit_attrs(attrs, ast::AttrStyle::Inner);
218 self.walk_block_stmts(b);
220 if !b.stmts.is_empty() {
221 if let Some(expr) = stmt_expr(&b.stmts[b.stmts.len() - 1]) {
222 if utils::semicolon_for_expr(&self.get_context(), expr) {
228 let rest_span = self.next_span(b.span.hi());
229 if out_of_file_lines_range!(self, rest_span) {
230 self.push_str(self.snippet(rest_span));
231 self.block_indent = self.block_indent.block_unindent(self.config);
233 // Ignore the closing brace.
234 let missing_span = self.next_span(b.span.hi() - brace_compensation);
235 self.close_block(missing_span, self.unindent_comment_on_closing_brace(b));
237 self.last_pos = source!(self, b.span).hi();
240 fn close_block(&mut self, span: Span, unindent_comment: bool) {
241 let config = self.config;
243 let mut last_hi = span.lo();
244 let mut unindented = false;
245 let mut prev_ends_with_newline = false;
246 let mut extra_newline = false;
248 let skip_normal = |s: &str| {
249 let trimmed = s.trim();
250 trimmed.is_empty() || trimmed.chars().all(|c| c == ';')
253 for (kind, offset, sub_slice) in CommentCodeSlices::new(self.snippet(span)) {
254 let sub_slice = transform_missing_snippet(config, sub_slice);
256 debug!("close_block: {:?} {:?} {:?}", kind, offset, sub_slice);
259 CodeCharKind::Comment => {
260 if !unindented && unindent_comment {
262 self.block_indent = self.block_indent.block_unindent(config);
264 let span_in_between = mk_sp(last_hi, span.lo() + BytePos::from_usize(offset));
265 let snippet_in_between = self.snippet(span_in_between);
266 let mut comment_on_same_line = !snippet_in_between.contains("\n");
268 let mut comment_shape =
269 Shape::indented(self.block_indent, config).comment(config);
270 if self.config.version() == Version::Two && comment_on_same_line {
272 // put the first line of the comment on the same line as the
274 match sub_slice.find("\n") {
276 self.push_str(&sub_slice);
278 Some(offset) if offset + 1 == sub_slice.len() => {
279 self.push_str(&sub_slice[..offset]);
282 let first_line = &sub_slice[..offset];
283 self.push_str(first_line);
284 self.push_str(&self.block_indent.to_string_with_newline(config));
286 // put the other lines below it, shaping it as needed
287 let other_lines = &sub_slice[offset + 1..];
289 rewrite_comment(other_lines, false, comment_shape, config);
291 Some(ref s) => self.push_str(s),
292 None => self.push_str(other_lines),
297 if comment_on_same_line {
298 // 1 = a space before `//`
299 let offset_len = 1 + last_line_width(&self.buffer)
300 .saturating_sub(self.block_indent.width());
302 .visual_indent(offset_len)
303 .sub_width(offset_len)
305 Some(shp) => comment_shape = shp,
306 None => comment_on_same_line = false,
310 if comment_on_same_line {
313 if count_newlines(snippet_in_between) >= 2 || extra_newline {
316 self.push_str(&self.block_indent.to_string_with_newline(config));
319 let comment_str = rewrite_comment(&sub_slice, false, comment_shape, config);
321 Some(ref s) => self.push_str(s),
322 None => self.push_str(&sub_slice),
326 CodeCharKind::Normal if skip_normal(&sub_slice) => {
327 extra_newline = prev_ends_with_newline && sub_slice.contains('\n');
330 CodeCharKind::Normal => {
331 self.push_str(&self.block_indent.to_string_with_newline(config));
332 self.push_str(sub_slice.trim());
335 prev_ends_with_newline = sub_slice.ends_with('\n');
336 extra_newline = false;
337 last_hi = span.lo() + BytePos::from_usize(offset + sub_slice.len());
340 self.block_indent = self.block_indent.block_indent(self.config);
342 self.block_indent = self.block_indent.block_unindent(self.config);
343 self.push_str(&self.block_indent.to_string_with_newline(config));
347 fn unindent_comment_on_closing_brace(&self, b: &ast::Block) -> bool {
348 self.is_if_else_block && !b.stmts.is_empty()
351 // Note that this only gets called for function definitions. Required methods
352 // on traits do not get handled here.
355 fk: visit::FnKind<'_>,
356 generics: &ast::Generics,
359 defaultness: ast::Defaultness,
360 inner_attrs: Option<&[ast::Attribute]>,
362 let indent = self.block_indent;
364 let rewrite = match fk {
365 visit::FnKind::Fn(_, ident, _, _, Some(ref b)) => {
367 self.rewrite_fn_before_block(
370 &FnSig::from_fn_kind(&fk, generics, fd, defaultness),
371 mk_sp(s.lo(), b.span.lo()),
377 if let Some((fn_str, fn_brace_style)) = rewrite {
378 self.format_missing_with_indent(source!(self, s).lo());
380 if let Some(rw) = self.single_line_fn(&fn_str, block, inner_attrs) {
382 self.last_pos = s.hi();
386 self.push_str(&fn_str);
387 match fn_brace_style {
388 FnBraceStyle::SameLine => self.push_str(" "),
389 FnBraceStyle::NextLine => {
390 self.push_str(&self.block_indent.to_string_with_newline(self.config))
394 self.last_pos = source!(self, block.span).lo();
396 self.format_missing(source!(self, block.span).lo());
399 self.visit_block(block, inner_attrs, true)
402 pub(crate) fn visit_item(&mut self, item: &ast::Item) {
403 skip_out_of_file_lines_range_visitor!(self, item.span);
405 // This is where we bail out if there is a skip attribute. This is only
406 // complex in the module case. It is complex because the module could be
407 // in a separate file and there might be attributes in both files, but
408 // the AST lumps them all together.
410 let mut attrs = &item.attrs;
411 let skip_context_saved = self.skip_context.clone();
412 self.skip_context.update_with_attrs(&attrs);
414 let should_visit_node_again = match item.kind {
415 // For use/extern crate items, skip rewriting attributes but check for a skip attribute.
416 ast::ItemKind::Use(..) | ast::ItemKind::ExternCrate(_) => {
417 if contains_skip(attrs) {
418 self.push_skipped_with_span(attrs.as_slice(), item.span(), item.span());
424 // Module is inline, in this case we treat it like any other item.
425 _ if !is_mod_decl(item) => {
426 if self.visit_attrs(&item.attrs, ast::AttrStyle::Outer) {
427 self.push_skipped_with_span(item.attrs.as_slice(), item.span(), item.span());
433 // Module is not inline, but should be skipped.
434 ast::ItemKind::Mod(..) if contains_skip(&item.attrs) => false,
435 // Module is not inline and should not be skipped. We want
436 // to process only the attributes in the current file.
437 ast::ItemKind::Mod(..) => {
438 filtered_attrs = filter_inline_attrs(&item.attrs, item.span());
439 // Assert because if we should skip it should be caught by
441 assert!(!self.visit_attrs(&filtered_attrs, ast::AttrStyle::Outer));
442 attrs = &filtered_attrs;
446 if self.visit_attrs(&item.attrs, ast::AttrStyle::Outer) {
447 self.push_skipped_with_span(item.attrs.as_slice(), item.span(), item.span());
455 if should_visit_node_again {
457 ast::ItemKind::Use(ref tree) => self.format_import(item, tree),
458 ast::ItemKind::Impl { .. } => {
459 let block_indent = self.block_indent;
460 let rw = self.with_context(|ctx| format_impl(&ctx, item, block_indent));
461 self.push_rewrite(item.span, rw);
463 ast::ItemKind::Trait(..) => {
464 let block_indent = self.block_indent;
465 let rw = self.with_context(|ctx| format_trait(&ctx, item, block_indent));
466 self.push_rewrite(item.span, rw);
468 ast::ItemKind::TraitAlias(ref generics, ref generic_bounds) => {
469 let shape = Shape::indented(self.block_indent, self.config);
470 let rw = format_trait_alias(
478 self.push_rewrite(item.span, rw);
480 ast::ItemKind::ExternCrate(_) => {
481 let rw = rewrite_extern_crate(&self.get_context(), item, self.shape());
482 let span = if attrs.is_empty() {
485 mk_sp(attrs[0].span.lo(), item.span.hi())
487 self.push_rewrite(span, rw);
489 ast::ItemKind::Struct(..) | ast::ItemKind::Union(..) => {
490 self.visit_struct(&StructParts::from_item(item));
492 ast::ItemKind::Enum(ref def, ref generics) => {
493 self.format_missing_with_indent(source!(self, item.span).lo());
494 self.visit_enum(item.ident, &item.vis, def, generics, item.span);
495 self.last_pos = source!(self, item.span).hi();
497 ast::ItemKind::Mod(ref module) => {
498 let is_inline = !is_mod_decl(item);
499 self.format_missing_with_indent(source!(self, item.span).lo());
500 self.format_mod(module, &item.vis, item.span, item.ident, attrs, is_inline);
502 ast::ItemKind::MacCall(ref mac) => {
503 self.visit_mac(mac, Some(item.ident), MacroPosition::Item);
505 ast::ItemKind::ForeignMod(ref foreign_mod) => {
506 self.format_missing_with_indent(source!(self, item.span).lo());
507 self.format_foreign_mod(foreign_mod, item.span);
509 ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => {
510 self.visit_static(&StaticParts::from_item(item));
512 ast::ItemKind::Fn(defaultness, ref fn_signature, ref generics, Some(ref body)) => {
513 let inner_attrs = inner_attributes(&item.attrs);
514 let fn_ctxt = match fn_signature.header.ext {
515 ast::Extern::None => visit::FnCtxt::Free,
516 _ => visit::FnCtxt::Foreign,
533 ast::ItemKind::Fn(_, ref fn_signature, ref generics, None) => {
534 let indent = self.block_indent;
535 let rewrite = self.rewrite_required_fn(
543 self.push_rewrite(item.span, rewrite);
545 ast::ItemKind::TyAlias(_, ref generics, ref generic_bounds, ref ty) => match ty {
547 let rewrite = rewrite_type_alias(
555 self.push_rewrite(item.span, rewrite);
558 let rewrite = rewrite_opaque_type(
566 self.push_rewrite(item.span, rewrite);
569 ast::ItemKind::GlobalAsm(..) => {
570 let snippet = Some(self.snippet(item.span).to_owned());
571 self.push_rewrite(item.span, snippet);
573 ast::ItemKind::MacroDef(ref def) => {
574 let rewrite = rewrite_macro_def(
583 self.push_rewrite(item.span, rewrite);
587 self.skip_context = skip_context_saved;
590 pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) {
591 skip_out_of_file_lines_range_visitor!(self, ti.span);
593 if self.visit_attrs(&ti.attrs, ast::AttrStyle::Outer) {
594 self.push_skipped_with_span(ti.attrs.as_slice(), ti.span(), ti.span());
599 ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_trait_item(ti)),
600 ast::AssocItemKind::Fn(_, ref sig, ref generics, None) => {
601 let indent = self.block_indent;
602 let rewrite = self.rewrite_required_fn(indent, ti.ident, sig, generics, ti.span);
603 self.push_rewrite(ti.span, rewrite);
605 ast::AssocItemKind::Fn(defaultness, ref sig, ref generics, Some(ref body)) => {
606 let inner_attrs = inner_attributes(&ti.attrs);
607 let vis = rustc_span::source_map::dummy_spanned(ast::VisibilityKind::Inherited);
608 let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Trait);
610 visit::FnKind::Fn(fn_ctxt, ti.ident, sig, &vis, Some(body)),
618 ast::AssocItemKind::TyAlias(_, ref generics, ref generic_bounds, ref type_default) => {
619 let rewrite = rewrite_associated_type(
621 type_default.as_ref(),
623 Some(generic_bounds),
627 self.push_rewrite(ti.span, rewrite);
629 ast::AssocItemKind::MacCall(ref mac) => {
630 self.visit_mac(mac, Some(ti.ident), MacroPosition::Item);
635 pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) {
636 skip_out_of_file_lines_range_visitor!(self, ii.span);
638 if self.visit_attrs(&ii.attrs, ast::AttrStyle::Outer) {
639 self.push_skipped_with_span(ii.attrs.as_slice(), ii.span, ii.span);
644 ast::AssocItemKind::Fn(defaultness, ref sig, ref generics, Some(ref body)) => {
645 let inner_attrs = inner_attributes(&ii.attrs);
646 let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Impl);
648 visit::FnKind::Fn(fn_ctxt, ii.ident, sig, &ii.vis, Some(body)),
656 ast::AssocItemKind::Fn(_, ref sig, ref generics, None) => {
657 let indent = self.block_indent;
658 let rewrite = self.rewrite_required_fn(indent, ii.ident, sig, generics, ii.span);
659 self.push_rewrite(ii.span, rewrite);
661 ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_impl_item(ii)),
662 ast::AssocItemKind::TyAlias(defaultness, ref generics, _, ref ty) => {
663 let rewrite_associated = || {
664 rewrite_associated_impl_type(
673 let rewrite = match ty {
674 None => rewrite_associated(),
675 Some(ty) => match ty.kind.opaque_top_hack() {
676 Some(generic_bounds) => rewrite_opaque_impl_type(
683 None => rewrite_associated(),
686 self.push_rewrite(ii.span, rewrite);
688 ast::AssocItemKind::MacCall(ref mac) => {
689 self.visit_mac(mac, Some(ii.ident), MacroPosition::Item);
694 fn visit_mac(&mut self, mac: &ast::MacCall, ident: Option<ast::Ident>, pos: MacroPosition) {
695 skip_out_of_file_lines_range_visitor!(self, mac.span());
698 let shape = self.shape().saturating_sub_width(1);
699 let rewrite = self.with_context(|ctx| rewrite_macro(mac, ident, ctx, shape, pos));
700 // As of v638 of the rustc-ap-* crates, the associated span no longer includes
701 // the trailing semicolon. This determines the correct span to ensure scenarios
702 // with whitespace between the delimiters and trailing semi (i.e. `foo!(abc) ;`)
703 // are formatted correctly.
704 let (span, rewrite) = match macro_style(mac, &self.get_context()) {
705 DelimToken::Bracket | DelimToken::Paren if MacroPosition::Item == pos => {
706 let search_span = mk_sp(mac.span().hi(), self.snippet_provider.end_pos());
707 let hi = self.snippet_provider.span_before(search_span, ";");
708 let target_span = mk_sp(mac.span().lo(), hi + BytePos(1));
709 let rewrite = rewrite.map(|rw| {
710 if !rw.ends_with(";") {
716 (target_span, rewrite)
718 _ => (mac.span(), rewrite),
721 self.push_rewrite(span, rewrite);
724 pub(crate) fn push_str(&mut self, s: &str) {
725 self.line_number += count_newlines(s);
726 self.buffer.push_str(s);
729 #[allow(clippy::needless_pass_by_value)]
730 fn push_rewrite_inner(&mut self, span: Span, rewrite: Option<String>) {
731 if let Some(ref s) = rewrite {
734 let snippet = self.snippet(span);
735 self.push_str(snippet.trim());
737 self.last_pos = source!(self, span).hi();
740 pub(crate) fn push_rewrite(&mut self, span: Span, rewrite: Option<String>) {
741 self.format_missing_with_indent(source!(self, span).lo());
742 self.push_rewrite_inner(span, rewrite);
745 pub(crate) fn push_skipped_with_span(
747 attrs: &[ast::Attribute],
751 self.format_missing_with_indent(source!(self, item_span).lo());
752 // do not take into account the lines with attributes as part of the skipped range
753 let attrs_end = attrs
755 .map(|attr| self.parse_sess.line_of_byte_pos(attr.span.hi()))
758 let first_line = self.parse_sess.line_of_byte_pos(main_span.lo());
759 // Statement can start after some newlines and/or spaces
760 // or it can be on the same line as the last attribute.
761 // So here we need to take a minimum between the two.
762 let lo = std::cmp::min(attrs_end + 1, first_line);
763 self.push_rewrite_inner(item_span, None);
764 let hi = self.line_number + 1;
765 self.skipped_range.borrow_mut().push((lo, hi));
768 pub(crate) fn from_context(ctx: &'a RewriteContext<'_>) -> FmtVisitor<'a> {
769 let mut visitor = FmtVisitor::from_parse_sess(
772 ctx.snippet_provider,
775 visitor.skip_context.update(ctx.skip_context.clone());
776 visitor.set_parent_context(ctx);
780 pub(crate) fn from_parse_sess(
781 parse_session: &'a ParseSess,
783 snippet_provider: &'a SnippetProvider,
784 report: FormatReport,
785 ) -> FmtVisitor<'a> {
787 parent_context: None,
788 parse_sess: parse_session,
789 buffer: String::with_capacity(snippet_provider.big_snippet.len() * 2),
790 last_pos: BytePos(0),
791 block_indent: Indent::empty(),
793 is_if_else_block: false,
796 skipped_range: Rc::new(RefCell::new(vec![])),
797 macro_rewrite_failure: false,
799 skip_context: Default::default(),
803 pub(crate) fn opt_snippet(&'b self, span: Span) -> Option<&'a str> {
804 self.snippet_provider.span_to_snippet(span)
807 pub(crate) fn snippet(&'b self, span: Span) -> &'a str {
808 self.opt_snippet(span).unwrap()
811 // Returns true if we should skip the following item.
812 pub(crate) fn visit_attrs(&mut self, attrs: &[ast::Attribute], style: ast::AttrStyle) -> bool {
814 if attr.check_name(depr_skip_annotation()) {
815 let file_name = self.parse_sess.span_to_filename(attr.span);
818 vec![FormattingError::from_span(
821 ErrorKind::DeprecatedAttr,
826 ast::AttrKind::Normal(ref attribute_item)
827 if self.is_unknown_rustfmt_attr(&attribute_item.path.segments) =>
829 let file_name = self.parse_sess.span_to_filename(attr.span);
832 vec![FormattingError::from_span(
843 if contains_skip(attrs) {
847 let attrs: Vec<_> = attrs.iter().filter(|a| a.style == style).cloned().collect();
848 if attrs.is_empty() {
852 let rewrite = attrs.rewrite(&self.get_context(), self.shape());
853 let span = mk_sp(attrs[0].span.lo(), attrs[attrs.len() - 1].span.hi());
854 self.push_rewrite(span, rewrite);
859 fn is_unknown_rustfmt_attr(&self, segments: &[ast::PathSegment]) -> bool {
860 if segments[0].ident.to_string() != "rustfmt" {
863 !is_skip_attr(segments)
866 fn walk_mod_items(&mut self, m: &ast::Mod) {
867 self.visit_items_with_reordering(&ptr_vec_to_ref_vec(&m.items));
870 fn walk_stmts(&mut self, stmts: &[Stmt<'_>]) {
871 if stmts.is_empty() {
875 // Extract leading `use ...;`.
876 let items: Vec<_> = stmts
878 .take_while(|stmt| stmt.to_item().map_or(false, is_use_item))
879 .filter_map(|stmt| stmt.to_item())
882 if items.is_empty() {
883 self.visit_stmt(&stmts[0]);
884 self.walk_stmts(&stmts[1..]);
886 self.visit_items_with_reordering(&items);
887 self.walk_stmts(&stmts[items.len()..]);
891 fn walk_block_stmts(&mut self, b: &ast::Block) {
892 self.walk_stmts(&Stmt::from_ast_nodes(b.stmts.iter()))
898 vis: &ast::Visibility,
901 attrs: &[ast::Attribute],
904 let vis_str = utils::format_visibility(&self.get_context(), vis);
905 self.push_str(&*vis_str);
906 self.push_str("mod ");
907 // Calling `to_owned()` to work around borrow checker.
908 let ident_str = rewrite_ident(&self.get_context(), ident).to_owned();
909 self.push_str(&ident_str);
912 match self.config.brace_style() {
913 BraceStyle::AlwaysNextLine => {
914 let indent_str = self.block_indent.to_string_with_newline(self.config);
915 self.push_str(&indent_str);
918 _ => self.push_str(" {"),
920 // Hackery to account for the closing }.
921 let mod_lo = self.snippet_provider.span_after(source!(self, s), "{");
923 self.snippet(mk_sp(mod_lo, source!(self, m.inner).hi() - BytePos(1)));
924 let body_snippet = body_snippet.trim();
925 if body_snippet.is_empty() {
928 self.last_pos = mod_lo;
929 self.block_indent = self.block_indent.block_indent(self.config);
930 self.visit_attrs(attrs, ast::AttrStyle::Inner);
931 self.walk_mod_items(m);
932 let missing_span = self.next_span(m.inner.hi() - BytePos(1));
933 self.close_block(missing_span, false);
935 self.last_pos = source!(self, m.inner).hi();
938 self.last_pos = source!(self, s).hi();
942 pub(crate) fn format_separate_mod(&mut self, m: &ast::Mod, end_pos: BytePos) {
943 self.block_indent = Indent::empty();
944 self.walk_mod_items(m);
945 self.format_missing_with_indent(end_pos);
948 pub(crate) fn skip_empty_lines(&mut self, end_pos: BytePos) {
949 while let Some(pos) = self
951 .opt_span_after(self.next_span(end_pos), "\n")
953 if let Some(snippet) = self.opt_snippet(self.next_span(pos)) {
954 if snippet.trim().is_empty() {
963 pub(crate) fn with_context<F>(&mut self, f: F) -> Option<String>
965 F: Fn(&RewriteContext<'_>) -> Option<String>,
967 let context = self.get_context();
968 let result = f(&context);
970 self.macro_rewrite_failure |= context.macro_rewrite_failure.get();
974 pub(crate) fn get_context(&self) -> RewriteContext<'_> {
976 parse_sess: self.parse_sess,
978 inside_macro: Rc::new(Cell::new(false)),
979 use_block: Cell::new(false),
980 is_if_else_block: Cell::new(false),
981 force_one_line_chain: Cell::new(false),
982 snippet_provider: self.snippet_provider,
983 macro_rewrite_failure: Cell::new(false),
984 report: self.report.clone(),
985 skip_context: self.skip_context.clone(),
986 skipped_range: self.skipped_range.clone(),