1 use std
::cell
::{Cell, RefCell}
;
4 use rustc_ast
::{ast, attr::HasAttrs, token::DelimToken, visit}
;
5 use rustc_span
::{symbol, BytePos, Pos, Span, DUMMY_SP}
;
8 use crate::comment
::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices}
;
9 use crate::config
::Version
;
10 use crate::config
::{BraceStyle, Config}
;
11 use crate::coverage
::transform_missing_snippet
;
13 format_impl
, format_trait
, format_trait_alias
, is_mod_decl
, is_use_item
,
14 rewrite_associated_impl_type
, rewrite_extern_crate
, rewrite_opaque_impl_type
,
15 rewrite_opaque_type
, rewrite_type_alias
, FnBraceStyle
, FnSig
, StaticParts
, StructParts
,
17 use crate::macros
::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition}
;
18 use crate::modules
::Module
;
19 use crate::rewrite
::{Rewrite, RewriteContext}
;
20 use crate::shape
::{Indent, Shape}
;
21 use crate::skip
::{is_skip_attr, SkipContext}
;
22 use crate::source_map
::{LineRangeUtils, SpanUtils}
;
23 use crate::spanned
::Spanned
;
24 use crate::stmt
::Stmt
;
25 use crate::syntux
::session
::ParseSess
;
27 self, contains_skip
, count_newlines
, depr_skip_annotation
, format_unsafety
, inner_attributes
,
28 last_line_width
, mk_sp
, ptr_vec_to_ref_vec
, rewrite_ident
, starts_with_newline
, stmt_expr
,
30 use crate::{ErrorKind, FormatReport, FormattingError}
;
32 /// Creates a string slice corresponding to the specified span.
33 pub(crate) struct SnippetProvider
{
34 /// A pointer to the content of the file we are formatting.
35 big_snippet
: Rc
<String
>,
36 /// A position of the start of `big_snippet`, used as an offset.
38 /// A end position of the file that this snippet lives.
42 impl SnippetProvider
{
43 pub(crate) fn span_to_snippet(&self, span
: Span
) -> Option
<&str> {
44 let start_index
= span
.lo().to_usize().checked_sub(self.start_pos
)?
;
45 let end_index
= span
.hi().to_usize().checked_sub(self.start_pos
)?
;
46 Some(&self.big_snippet
[start_index
..end_index
])
49 pub(crate) fn new(start_pos
: BytePos
, end_pos
: BytePos
, big_snippet
: Rc
<String
>) -> Self {
50 let start_pos
= start_pos
.to_usize();
51 let end_pos
= end_pos
.to_usize();
59 pub(crate) fn entire_snippet(&self) -> &str {
60 self.big_snippet
.as_str()
63 pub(crate) fn start_pos(&self) -> BytePos
{
64 BytePos
::from_usize(self.start_pos
)
67 pub(crate) fn end_pos(&self) -> BytePos
{
68 BytePos
::from_usize(self.end_pos
)
72 pub(crate) struct FmtVisitor
<'a
> {
73 parent_context
: Option
<&'a RewriteContext
<'a
>>,
74 pub(crate) parse_sess
: &'a ParseSess
,
75 pub(crate) buffer
: String
,
76 pub(crate) last_pos
: BytePos
,
77 // FIXME: use an RAII util or closure for indenting
78 pub(crate) block_indent
: Indent
,
79 pub(crate) config
: &'a Config
,
80 pub(crate) is_if_else_block
: bool
,
81 pub(crate) snippet_provider
: &'a SnippetProvider
,
82 pub(crate) line_number
: usize,
83 /// List of 1-based line ranges which were annotated with skip
84 /// Both bounds are inclusifs.
85 pub(crate) skipped_range
: Rc
<RefCell
<Vec
<(usize, usize)>>>,
86 pub(crate) macro_rewrite_failure
: bool
,
87 pub(crate) report
: FormatReport
,
88 pub(crate) skip_context
: SkipContext
,
89 pub(crate) is_macro_def
: bool
,
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
<'_
>, include_empty_semi
: bool
) {
118 self.parse_sess
.span_to_debug_info(stmt
.span())
122 // If the statement is empty, just skip over it. Before that, make sure any comment
123 // snippet preceding the semicolon is picked up.
124 let snippet
= self.snippet(mk_sp(self.last_pos
, stmt
.span().lo()));
125 let original_starts_with_newline
= snippet
127 .map_or(false, |i
| starts_with_newline(&snippet
[i
..]));
128 let snippet
= snippet
.trim();
129 if !snippet
.is_empty() {
130 // FIXME(calebcartwright 2021-01-03) - This exists strictly to maintain legacy
131 // formatting where rustfmt would preserve redundant semicolons on Items in a
132 // statement position.
133 // See comment within `walk_stmts` for more info
134 if include_empty_semi
{
135 self.format_missing(stmt
.span().hi());
137 if original_starts_with_newline
{
141 self.push_str(&self.block_indent
.to_string(self.config
));
142 self.push_str(snippet
);
144 } else if include_empty_semi
{
147 self.last_pos
= stmt
.span().hi();
151 match stmt
.as_ast_node().kind
{
152 ast
::StmtKind
::Item(ref item
) => {
153 self.visit_item(item
);
154 self.last_pos
= stmt
.span().hi();
156 ast
::StmtKind
::Local(..) | ast
::StmtKind
::Expr(..) | ast
::StmtKind
::Semi(..) => {
157 let attrs
= get_attrs_from_stmt(stmt
.as_ast_node());
158 if contains_skip(attrs
) {
159 self.push_skipped_with_span(
162 get_span_without_attrs(stmt
.as_ast_node()),
165 let shape
= self.shape();
166 let rewrite
= self.with_context(|ctx
| stmt
.rewrite(&ctx
, shape
));
167 self.push_rewrite(stmt
.span(), rewrite
)
170 ast
::StmtKind
::MacCall(ref mac_stmt
) => {
171 if self.visit_attrs(&mac_stmt
.attrs
, ast
::AttrStyle
::Outer
) {
172 self.push_skipped_with_span(
175 get_span_without_attrs(stmt
.as_ast_node()),
178 self.visit_mac(&mac_stmt
.mac
, None
, MacroPosition
::Statement
);
180 self.format_missing(stmt
.span().hi());
182 ast
::StmtKind
::Empty
=> (),
186 /// Remove spaces between the opening brace and the first statement or the inner attribute
188 fn trim_spaces_after_opening_brace(
191 inner_attrs
: Option
<&[ast
::Attribute
]>,
193 if let Some(first_stmt
) = b
.stmts
.first() {
195 .and_then(|attrs
| inner_attributes(attrs
).first().map(|attr
| attr
.span
.lo()))
196 .unwrap_or_else(|| first_stmt
.span().lo());
197 let missing_span
= self.next_span(hi
);
198 let snippet
= self.snippet(missing_span
);
199 let len
= CommentCodeSlices
::new(snippet
)
201 .and_then(|(kind
, _
, s
)| {
202 if kind
== CodeCharKind
::Normal
{
208 if let Some(len
) = len
{
209 self.last_pos
= self.last_pos
+ BytePos
::from_usize(len
);
214 pub(crate) fn visit_block(
217 inner_attrs
: Option
<&[ast
::Attribute
]>,
222 self.parse_sess
.span_to_debug_info(b
.span
),
225 // Check if this block has braces.
226 let brace_compensation
= BytePos(if has_braces { 1 }
else { 0 }
);
228 self.last_pos
= self.last_pos
+ brace_compensation
;
229 self.block_indent
= self.block_indent
.block_indent(self.config
);
231 self.trim_spaces_after_opening_brace(b
, inner_attrs
);
233 // Format inner attributes if available.
234 if let Some(attrs
) = inner_attrs
{
235 self.visit_attrs(attrs
, ast
::AttrStyle
::Inner
);
238 self.walk_block_stmts(b
);
240 if !b
.stmts
.is_empty() {
241 if let Some(expr
) = stmt_expr(&b
.stmts
[b
.stmts
.len() - 1]) {
242 if utils
::semicolon_for_expr(&self.get_context(), expr
) {
248 let rest_span
= self.next_span(b
.span
.hi());
249 if out_of_file_lines_range
!(self, rest_span
) {
250 self.push_str(self.snippet(rest_span
));
251 self.block_indent
= self.block_indent
.block_unindent(self.config
);
253 // Ignore the closing brace.
254 let missing_span
= self.next_span(b
.span
.hi() - brace_compensation
);
255 self.close_block(missing_span
, self.unindent_comment_on_closing_brace(b
));
257 self.last_pos
= source
!(self, b
.span
).hi();
260 fn close_block(&mut self, span
: Span
, unindent_comment
: bool
) {
261 let config
= self.config
;
263 let mut last_hi
= span
.lo();
264 let mut unindented
= false;
265 let mut prev_ends_with_newline
= false;
266 let mut extra_newline
= false;
268 let skip_normal
= |s
: &str| {
269 let trimmed
= s
.trim();
270 trimmed
.is_empty() || trimmed
.chars().all(|c
| c
== '
;'
)
273 let comment_snippet
= self.snippet(span
);
275 let align_to_right
= if unindent_comment
&& contains_comment(&comment_snippet
) {
276 let first_lines
= comment_snippet
.splitn(2, '
/'
).next().unwrap_or("");
277 last_line_width(first_lines
) > last_line_width(&comment_snippet
)
282 for (kind
, offset
, sub_slice
) in CommentCodeSlices
::new(comment_snippet
) {
283 let sub_slice
= transform_missing_snippet(config
, sub_slice
);
285 debug
!("close_block: {:?} {:?} {:?}", kind
, offset
, sub_slice
);
288 CodeCharKind
::Comment
=> {
289 if !unindented
&& unindent_comment
&& !align_to_right
{
291 self.block_indent
= self.block_indent
.block_unindent(config
);
293 let span_in_between
= mk_sp(last_hi
, span
.lo() + BytePos
::from_usize(offset
));
294 let snippet_in_between
= self.snippet(span_in_between
);
295 let mut comment_on_same_line
= !snippet_in_between
.contains("\n");
297 let mut comment_shape
=
298 Shape
::indented(self.block_indent
, config
).comment(config
);
299 if self.config
.version() == Version
::Two
&& comment_on_same_line
{
301 // put the first line of the comment on the same line as the
303 match sub_slice
.find("\n") {
305 self.push_str(&sub_slice
);
307 Some(offset
) if offset
+ 1 == sub_slice
.len() => {
308 self.push_str(&sub_slice
[..offset
]);
311 let first_line
= &sub_slice
[..offset
];
312 self.push_str(first_line
);
313 self.push_str(&self.block_indent
.to_string_with_newline(config
));
315 // put the other lines below it, shaping it as needed
316 let other_lines
= &sub_slice
[offset
+ 1..];
318 rewrite_comment(other_lines
, false, comment_shape
, config
);
320 Some(ref s
) => self.push_str(s
),
321 None
=> self.push_str(other_lines
),
326 if comment_on_same_line
{
327 // 1 = a space before `//`
328 let offset_len
= 1 + last_line_width(&self.buffer
)
329 .saturating_sub(self.block_indent
.width());
331 .visual_indent(offset_len
)
332 .sub_width(offset_len
)
334 Some(shp
) => comment_shape
= shp
,
335 None
=> comment_on_same_line
= false,
339 if comment_on_same_line
{
342 if count_newlines(snippet_in_between
) >= 2 || extra_newline
{
345 self.push_str(&self.block_indent
.to_string_with_newline(config
));
348 let comment_str
= rewrite_comment(&sub_slice
, false, comment_shape
, config
);
350 Some(ref s
) => self.push_str(s
),
351 None
=> self.push_str(&sub_slice
),
355 CodeCharKind
::Normal
if skip_normal(&sub_slice
) => {
356 extra_newline
= prev_ends_with_newline
&& sub_slice
.contains('
\n'
);
359 CodeCharKind
::Normal
=> {
360 self.push_str(&self.block_indent
.to_string_with_newline(config
));
361 self.push_str(sub_slice
.trim());
364 prev_ends_with_newline
= sub_slice
.ends_with('
\n'
);
365 extra_newline
= false;
366 last_hi
= span
.lo() + BytePos
::from_usize(offset
+ sub_slice
.len());
369 self.block_indent
= self.block_indent
.block_indent(self.config
);
371 self.block_indent
= self.block_indent
.block_unindent(self.config
);
372 self.push_str(&self.block_indent
.to_string_with_newline(config
));
376 fn unindent_comment_on_closing_brace(&self, b
: &ast
::Block
) -> bool
{
377 self.is_if_else_block
&& !b
.stmts
.is_empty()
380 // Note that this only gets called for function definitions. Required methods
381 // on traits do not get handled here.
382 pub(crate) fn visit_fn(
384 fk
: visit
::FnKind
<'_
>,
385 generics
: &ast
::Generics
,
388 defaultness
: ast
::Defaultness
,
389 inner_attrs
: Option
<&[ast
::Attribute
]>,
391 let indent
= self.block_indent
;
393 let rewrite
= match fk
{
394 visit
::FnKind
::Fn(_
, ident
, _
, _
, Some(ref b
)) => {
396 self.rewrite_fn_before_block(
399 &FnSig
::from_fn_kind(&fk
, generics
, fd
, defaultness
),
400 mk_sp(s
.lo(), b
.span
.lo()),
406 if let Some((fn_str
, fn_brace_style
)) = rewrite
{
407 self.format_missing_with_indent(source
!(self, s
).lo());
409 if let Some(rw
) = self.single_line_fn(&fn_str
, block
, inner_attrs
) {
411 self.last_pos
= s
.hi();
415 self.push_str(&fn_str
);
416 match fn_brace_style
{
417 FnBraceStyle
::SameLine
=> self.push_str(" "),
418 FnBraceStyle
::NextLine
=> {
419 self.push_str(&self.block_indent
.to_string_with_newline(self.config
))
423 self.last_pos
= source
!(self, block
.span
).lo();
425 self.format_missing(source
!(self, block
.span
).lo());
428 self.visit_block(block
, inner_attrs
, true)
431 pub(crate) fn visit_item(&mut self, item
: &ast
::Item
) {
432 skip_out_of_file_lines_range_visitor
!(self, item
.span
);
434 // This is where we bail out if there is a skip attribute. This is only
435 // complex in the module case. It is complex because the module could be
436 // in a separate file and there might be attributes in both files, but
437 // the AST lumps them all together.
439 let mut attrs
= &item
.attrs
;
440 let skip_context_saved
= self.skip_context
.clone();
441 self.skip_context
.update_with_attrs(&attrs
);
443 let should_visit_node_again
= match item
.kind
{
444 // For use/extern crate items, skip rewriting attributes but check for a skip attribute.
445 ast
::ItemKind
::Use(..) | ast
::ItemKind
::ExternCrate(_
) => {
446 if contains_skip(attrs
) {
447 self.push_skipped_with_span(attrs
.as_slice(), item
.span(), item
.span());
453 // Module is inline, in this case we treat it like any other item.
454 _
if !is_mod_decl(item
) => {
455 if self.visit_attrs(&item
.attrs
, ast
::AttrStyle
::Outer
) {
456 self.push_skipped_with_span(item
.attrs
.as_slice(), item
.span(), item
.span());
462 // Module is not inline, but should be skipped.
463 ast
::ItemKind
::Mod(..) if contains_skip(&item
.attrs
) => false,
464 // Module is not inline and should not be skipped. We want
465 // to process only the attributes in the current file.
466 ast
::ItemKind
::Mod(..) => {
467 filtered_attrs
= filter_inline_attrs(&item
.attrs
, item
.span());
468 // Assert because if we should skip it should be caught by
470 assert
!(!self.visit_attrs(&filtered_attrs
, ast
::AttrStyle
::Outer
));
471 attrs
= &filtered_attrs
;
475 if self.visit_attrs(&item
.attrs
, ast
::AttrStyle
::Outer
) {
476 self.push_skipped_with_span(item
.attrs
.as_slice(), item
.span(), item
.span());
484 // TODO(calebcartwright): consider enabling box_patterns feature gate
485 if should_visit_node_again
{
487 ast
::ItemKind
::Use(ref tree
) => self.format_import(item
, tree
),
488 ast
::ItemKind
::Impl { .. }
=> {
489 let block_indent
= self.block_indent
;
490 let rw
= self.with_context(|ctx
| format_impl(&ctx
, item
, block_indent
));
491 self.push_rewrite(item
.span
, rw
);
493 ast
::ItemKind
::Trait(..) => {
494 let block_indent
= self.block_indent
;
495 let rw
= self.with_context(|ctx
| format_trait(&ctx
, item
, block_indent
));
496 self.push_rewrite(item
.span
, rw
);
498 ast
::ItemKind
::TraitAlias(ref generics
, ref generic_bounds
) => {
499 let shape
= Shape
::indented(self.block_indent
, self.config
);
500 let rw
= format_trait_alias(
508 self.push_rewrite(item
.span
, rw
);
510 ast
::ItemKind
::ExternCrate(_
) => {
511 let rw
= rewrite_extern_crate(&self.get_context(), item
, self.shape());
512 let span
= if attrs
.is_empty() {
515 mk_sp(attrs
[0].span
.lo(), item
.span
.hi())
517 self.push_rewrite(span
, rw
);
519 ast
::ItemKind
::Struct(..) | ast
::ItemKind
::Union(..) => {
520 self.visit_struct(&StructParts
::from_item(item
));
522 ast
::ItemKind
::Enum(ref def
, ref generics
) => {
523 self.format_missing_with_indent(source
!(self, item
.span
).lo());
524 self.visit_enum(item
.ident
, &item
.vis
, def
, generics
, item
.span
);
525 self.last_pos
= source
!(self, item
.span
).hi();
527 ast
::ItemKind
::Mod(ref module
) => {
528 let is_inline
= !is_mod_decl(item
);
529 self.format_missing_with_indent(source
!(self, item
.span
).lo());
530 self.format_mod(module
, &item
.vis
, item
.span
, item
.ident
, attrs
, is_inline
);
532 ast
::ItemKind
::MacCall(ref mac
) => {
533 self.visit_mac(mac
, Some(item
.ident
), MacroPosition
::Item
);
535 ast
::ItemKind
::ForeignMod(ref foreign_mod
) => {
536 self.format_missing_with_indent(source
!(self, item
.span
).lo());
537 self.format_foreign_mod(foreign_mod
, item
.span
);
539 ast
::ItemKind
::Static(..) | ast
::ItemKind
::Const(..) => {
540 self.visit_static(&StaticParts
::from_item(item
));
542 ast
::ItemKind
::Fn(ref fn_kind
) => {
543 let ast
::FnKind(defaultness
, ref fn_signature
, ref generics
, ref block
) =
545 if let Some(ref body
) = block
{
546 let inner_attrs
= inner_attributes(&item
.attrs
);
547 let fn_ctxt
= match fn_signature
.header
.ext
{
548 ast
::Extern
::None
=> visit
::FnCtxt
::Free
,
549 _
=> visit
::FnCtxt
::Foreign
,
566 let indent
= self.block_indent
;
567 let rewrite
= self.rewrite_required_fn(
574 self.push_rewrite(item
.span
, rewrite
);
577 ast
::ItemKind
::TyAlias(ref alias_kind
) => {
578 let ast
::TyAliasKind(_
, ref generics
, ref generic_bounds
, ref ty
) =
582 let rewrite
= rewrite_type_alias(
586 Some(generic_bounds
),
592 self.push_rewrite(item
.span
, rewrite
);
595 let rewrite
= rewrite_opaque_type(
604 self.push_rewrite(item
.span
, rewrite
);
608 ast
::ItemKind
::GlobalAsm(..) => {
609 let snippet
= Some(self.snippet(item
.span
).to_owned());
610 self.push_rewrite(item
.span
, snippet
);
612 ast
::ItemKind
::MacroDef(ref def
) => {
613 let rewrite
= rewrite_macro_def(
622 self.push_rewrite(item
.span
, rewrite
);
626 self.skip_context
= skip_context_saved
;
629 pub(crate) fn visit_trait_item(&mut self, ti
: &ast
::AssocItem
) {
630 skip_out_of_file_lines_range_visitor
!(self, ti
.span
);
632 if self.visit_attrs(&ti
.attrs
, ast
::AttrStyle
::Outer
) {
633 self.push_skipped_with_span(ti
.attrs
.as_slice(), ti
.span(), ti
.span());
637 // TODO(calebcartwright): consider enabling box_patterns feature gate
639 ast
::AssocItemKind
::Const(..) => self.visit_static(&StaticParts
::from_trait_item(ti
)),
640 ast
::AssocItemKind
::Fn(ref fn_kind
) => {
641 let ast
::FnKind(defaultness
, ref sig
, ref generics
, ref block
) = **fn_kind
;
642 if let Some(ref body
) = block
{
643 let inner_attrs
= inner_attributes(&ti
.attrs
);
644 let vis
= ast
::Visibility
{
645 kind
: ast
::VisibilityKind
::Inherited
,
649 let fn_ctxt
= visit
::FnCtxt
::Assoc(visit
::AssocCtxt
::Trait
);
651 visit
::FnKind
::Fn(fn_ctxt
, ti
.ident
, sig
, &vis
, Some(body
)),
659 let indent
= self.block_indent
;
661 self.rewrite_required_fn(indent
, ti
.ident
, sig
, generics
, ti
.span
);
662 self.push_rewrite(ti
.span
, rewrite
);
665 ast
::AssocItemKind
::TyAlias(ref ty_alias_kind
) => {
666 let ast
::TyAliasKind(_
, ref generics
, ref generic_bounds
, ref type_default
) =
668 let rewrite
= rewrite_type_alias(
670 type_default
.as_ref(),
672 Some(generic_bounds
),
678 self.push_rewrite(ti
.span
, rewrite
);
680 ast
::AssocItemKind
::MacCall(ref mac
) => {
681 self.visit_mac(mac
, Some(ti
.ident
), MacroPosition
::Item
);
686 pub(crate) fn visit_impl_item(&mut self, ii
: &ast
::AssocItem
) {
687 skip_out_of_file_lines_range_visitor
!(self, ii
.span
);
689 if self.visit_attrs(&ii
.attrs
, ast
::AttrStyle
::Outer
) {
690 self.push_skipped_with_span(ii
.attrs
.as_slice(), ii
.span
, ii
.span
);
695 ast
::AssocItemKind
::Fn(ref fn_kind
) => {
696 let ast
::FnKind(defaultness
, ref sig
, ref generics
, ref block
) = **fn_kind
;
697 if let Some(ref body
) = block
{
698 let inner_attrs
= inner_attributes(&ii
.attrs
);
699 let fn_ctxt
= visit
::FnCtxt
::Assoc(visit
::AssocCtxt
::Impl
);
701 visit
::FnKind
::Fn(fn_ctxt
, ii
.ident
, sig
, &ii
.vis
, Some(body
)),
709 let indent
= self.block_indent
;
711 self.rewrite_required_fn(indent
, ii
.ident
, sig
, generics
, ii
.span
);
712 self.push_rewrite(ii
.span
, rewrite
);
715 ast
::AssocItemKind
::Const(..) => self.visit_static(&StaticParts
::from_impl_item(ii
)),
716 ast
::AssocItemKind
::TyAlias(ref ty_alias_kind
) => {
717 let ast
::TyAliasKind(defaultness
, ref generics
, _
, ref ty
) = **ty_alias_kind
;
718 let rewrite_associated
= || {
719 rewrite_associated_impl_type(
730 let rewrite
= match ty
{
731 None
=> rewrite_associated(),
732 Some(ty
) => match ty
.kind
{
733 ast
::TyKind
::ImplTrait(_
, ref bounds
) => rewrite_opaque_impl_type(
740 _
=> rewrite_associated(),
743 self.push_rewrite(ii
.span
, rewrite
);
745 ast
::AssocItemKind
::MacCall(ref mac
) => {
746 self.visit_mac(mac
, Some(ii
.ident
), MacroPosition
::Item
);
751 fn visit_mac(&mut self, mac
: &ast
::MacCall
, ident
: Option
<symbol
::Ident
>, pos
: MacroPosition
) {
752 skip_out_of_file_lines_range_visitor
!(self, mac
.span());
755 let shape
= self.shape().saturating_sub_width(1);
756 let rewrite
= self.with_context(|ctx
| rewrite_macro(mac
, ident
, ctx
, shape
, pos
));
757 // As of v638 of the rustc-ap-* crates, the associated span no longer includes
758 // the trailing semicolon. This determines the correct span to ensure scenarios
759 // with whitespace between the delimiters and trailing semi (i.e. `foo!(abc) ;`)
760 // are formatted correctly.
761 let (span
, rewrite
) = match macro_style(mac
, &self.get_context()) {
762 DelimToken
::Bracket
| DelimToken
::Paren
if MacroPosition
::Item
== pos
=> {
763 let search_span
= mk_sp(mac
.span().hi(), self.snippet_provider
.end_pos());
764 let hi
= self.snippet_provider
.span_before(search_span
, ";");
765 let target_span
= mk_sp(mac
.span().lo(), hi
+ BytePos(1));
766 let rewrite
= rewrite
.map(|rw
| {
767 if !rw
.ends_with(";") {
773 (target_span
, rewrite
)
775 _
=> (mac
.span(), rewrite
),
778 self.push_rewrite(span
, rewrite
);
781 pub(crate) fn push_str(&mut self, s
: &str) {
782 self.line_number
+= count_newlines(s
);
783 self.buffer
.push_str(s
);
786 #[allow(clippy::needless_pass_by_value)]
787 fn push_rewrite_inner(&mut self, span
: Span
, rewrite
: Option
<String
>) {
788 if let Some(ref s
) = rewrite
{
791 let snippet
= self.snippet(span
);
792 self.push_str(snippet
.trim());
794 self.last_pos
= source
!(self, span
).hi();
797 pub(crate) fn push_rewrite(&mut self, span
: Span
, rewrite
: Option
<String
>) {
798 self.format_missing_with_indent(source
!(self, span
).lo());
799 self.push_rewrite_inner(span
, rewrite
);
802 pub(crate) fn push_skipped_with_span(
804 attrs
: &[ast
::Attribute
],
808 self.format_missing_with_indent(source
!(self, item_span
).lo());
809 // do not take into account the lines with attributes as part of the skipped range
810 let attrs_end
= attrs
812 .map(|attr
| self.parse_sess
.line_of_byte_pos(attr
.span
.hi()))
815 let first_line
= self.parse_sess
.line_of_byte_pos(main_span
.lo());
816 // Statement can start after some newlines and/or spaces
817 // or it can be on the same line as the last attribute.
818 // So here we need to take a minimum between the two.
819 let lo
= std
::cmp
::min(attrs_end
+ 1, first_line
);
820 self.push_rewrite_inner(item_span
, None
);
821 let hi
= self.line_number
+ 1;
822 self.skipped_range
.borrow_mut().push((lo
, hi
));
825 pub(crate) fn from_context(ctx
: &'a RewriteContext
<'_
>) -> FmtVisitor
<'a
> {
826 let mut visitor
= FmtVisitor
::from_parse_sess(
829 ctx
.snippet_provider
,
832 visitor
.skip_context
.update(ctx
.skip_context
.clone());
833 visitor
.set_parent_context(ctx
);
837 pub(crate) fn from_parse_sess(
838 parse_session
: &'a ParseSess
,
840 snippet_provider
: &'a SnippetProvider
,
841 report
: FormatReport
,
842 ) -> FmtVisitor
<'a
> {
844 parent_context
: None
,
845 parse_sess
: parse_session
,
846 buffer
: String
::with_capacity(snippet_provider
.big_snippet
.len() * 2),
847 last_pos
: BytePos(0),
848 block_indent
: Indent
::empty(),
850 is_if_else_block
: false,
853 skipped_range
: Rc
::new(RefCell
::new(vec
![])),
855 macro_rewrite_failure
: false,
857 skip_context
: Default
::default(),
861 pub(crate) fn opt_snippet(&'b
self, span
: Span
) -> Option
<&'a
str> {
862 self.snippet_provider
.span_to_snippet(span
)
865 pub(crate) fn snippet(&'b
self, span
: Span
) -> &'a
str {
866 self.opt_snippet(span
).unwrap()
869 // Returns true if we should skip the following item.
870 pub(crate) fn visit_attrs(&mut self, attrs
: &[ast
::Attribute
], style
: ast
::AttrStyle
) -> bool
{
872 if attr
.has_name(depr_skip_annotation()) {
873 let file_name
= self.parse_sess
.span_to_filename(attr
.span
);
876 vec
![FormattingError
::from_span(
879 ErrorKind
::DeprecatedAttr
,
884 ast
::AttrKind
::Normal(ref attribute_item
, _
)
885 if self.is_unknown_rustfmt_attr(&attribute_item
.path
.segments
) =>
887 let file_name
= self.parse_sess
.span_to_filename(attr
.span
);
890 vec
![FormattingError
::from_span(
901 if contains_skip(attrs
) {
905 let attrs
: Vec
<_
> = attrs
.iter().filter(|a
| a
.style
== style
).cloned().collect();
906 if attrs
.is_empty() {
910 let rewrite
= attrs
.rewrite(&self.get_context(), self.shape());
911 let span
= mk_sp(attrs
[0].span
.lo(), attrs
[attrs
.len() - 1].span
.hi());
912 self.push_rewrite(span
, rewrite
);
917 fn is_unknown_rustfmt_attr(&self, segments
: &[ast
::PathSegment
]) -> bool
{
918 if segments
[0].ident
.to_string() != "rustfmt" {
921 !is_skip_attr(segments
)
924 fn walk_mod_items(&mut self, m
: &ast
::Mod
) {
925 self.visit_items_with_reordering(&ptr_vec_to_ref_vec(&m
.items
));
928 fn walk_stmts(&mut self, stmts
: &[Stmt
<'_
>], include_current_empty_semi
: bool
) {
929 if stmts
.is_empty() {
933 // Extract leading `use ...;`.
934 let items
: Vec
<_
> = stmts
936 .take_while(|stmt
| stmt
.to_item().map_or(false, is_use_item
))
937 .filter_map(|stmt
| stmt
.to_item())
940 if items
.is_empty() {
941 self.visit_stmt(&stmts
[0], include_current_empty_semi
);
943 // FIXME(calebcartwright 2021-01-03) - This exists strictly to maintain legacy
944 // formatting where rustfmt would preserve redundant semicolons on Items in a
945 // statement position.
947 // Starting in rustc-ap-* v692 (~2020-12-01) the rustc parser now parses this as
948 // two separate statements (Item and Empty kinds), whereas before it was parsed as
949 // a single statement with the statement's span including the redundant semicolon.
951 // rustfmt typically tosses unnecessary/redundant semicolons, and eventually we
952 // should toss these as well, but doing so at this time would
953 // break the Stability Guarantee
954 // N.B. This could be updated to utilize the version gates.
955 let include_next_empty
= if stmts
.len() > 1 {
956 match (&stmts
[0].as_ast_node().kind
, &stmts
[1].as_ast_node().kind
) {
957 (ast
::StmtKind
::Item(_
), ast
::StmtKind
::Empty
) => true,
964 self.walk_stmts(&stmts
[1..], include_next_empty
);
966 self.visit_items_with_reordering(&items
);
967 self.walk_stmts(&stmts
[items
.len()..], false);
971 fn walk_block_stmts(&mut self, b
: &ast
::Block
) {
972 self.walk_stmts(&Stmt
::from_ast_nodes(b
.stmts
.iter()), false)
978 vis
: &ast
::Visibility
,
980 ident
: symbol
::Ident
,
981 attrs
: &[ast
::Attribute
],
984 let vis_str
= utils
::format_visibility(&self.get_context(), vis
);
985 self.push_str(&*vis_str
);
986 self.push_str(format_unsafety(m
.unsafety
));
987 self.push_str("mod ");
988 // Calling `to_owned()` to work around borrow checker.
989 let ident_str
= rewrite_ident(&self.get_context(), ident
).to_owned();
990 self.push_str(&ident_str
);
993 match self.config
.brace_style() {
994 BraceStyle
::AlwaysNextLine
=> {
995 let indent_str
= self.block_indent
.to_string_with_newline(self.config
);
996 self.push_str(&indent_str
);
999 _
=> self.push_str(" {"),
1001 // Hackery to account for the closing }.
1002 let mod_lo
= self.snippet_provider
.span_after(source
!(self, s
), "{");
1004 self.snippet(mk_sp(mod_lo
, source
!(self, m
.inner
).hi() - BytePos(1)));
1005 let body_snippet
= body_snippet
.trim();
1006 if body_snippet
.is_empty() {
1009 self.last_pos
= mod_lo
;
1010 self.block_indent
= self.block_indent
.block_indent(self.config
);
1011 self.visit_attrs(attrs
, ast
::AttrStyle
::Inner
);
1012 self.walk_mod_items(m
);
1013 let missing_span
= self.next_span(m
.inner
.hi() - BytePos(1));
1014 self.close_block(missing_span
, false);
1016 self.last_pos
= source
!(self, m
.inner
).hi();
1019 self.last_pos
= source
!(self, s
).hi();
1023 pub(crate) fn format_separate_mod(&mut self, m
: &Module
<'_
>, end_pos
: BytePos
) {
1024 self.block_indent
= Indent
::empty();
1025 if self.visit_attrs(m
.attrs(), ast
::AttrStyle
::Inner
) {
1026 self.push_skipped_with_span(m
.attrs(), m
.as_ref().inner
, m
.as_ref().inner
);
1028 self.walk_mod_items(m
.as_ref());
1029 self.format_missing_with_indent(end_pos
);
1033 pub(crate) fn skip_empty_lines(&mut self, end_pos
: BytePos
) {
1034 while let Some(pos
) = self
1036 .opt_span_after(self.next_span(end_pos
), "\n")
1038 if let Some(snippet
) = self.opt_snippet(self.next_span(pos
)) {
1039 if snippet
.trim().is_empty() {
1040 self.last_pos
= pos
;
1048 pub(crate) fn with_context
<F
>(&mut self, f
: F
) -> Option
<String
>
1050 F
: Fn(&RewriteContext
<'_
>) -> Option
<String
>,
1052 let context
= self.get_context();
1053 let result
= f(&context
);
1055 self.macro_rewrite_failure
|= context
.macro_rewrite_failure
.get();
1059 pub(crate) fn get_context(&self) -> RewriteContext
<'_
> {
1061 parse_sess
: self.parse_sess
,
1062 config
: self.config
,
1063 inside_macro
: Rc
::new(Cell
::new(false)),
1064 use_block
: Cell
::new(false),
1065 is_if_else_block
: Cell
::new(false),
1066 force_one_line_chain
: Cell
::new(false),
1067 snippet_provider
: self.snippet_provider
,
1068 macro_rewrite_failure
: Cell
::new(false),
1069 is_macro_def
: self.is_macro_def
,
1070 report
: self.report
.clone(),
1071 skip_context
: self.skip_context
.clone(),
1072 skipped_range
: self.skipped_range
.clone(),