1 use std::cell::{Cell, RefCell}; 2 use std::rc::Rc; 3 4 use rustc_ast::{ast, token::Delimiter, visit}; 5 use rustc_data_structures::sync::Lrc; 6 use rustc_span::{symbol, BytePos, Pos, Span}; 7 8 use crate::attr::*; 9 use crate::comment::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices}; 10 use crate::config::Version; 11 use crate::config::{BraceStyle, Config, MacroSelector}; 12 use crate::coverage::transform_missing_snippet; 13 use crate::items::{ 14 format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate, 15 rewrite_type_alias, FnBraceStyle, FnSig, ItemVisitorKind, StaticParts, StructParts, 16 }; 17 use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition}; 18 use crate::modules::Module; 19 use crate::parse::session::ParseSess; 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::utils::{ 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, 29 }; 30 use crate::{ErrorKind, FormatReport, FormattingError}; 31 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: Lrc<String>, 36 /// A position of the start of `big_snippet`, used as an offset. 37 start_pos: usize, 38 /// An end position of the file that this snippet lives. 39 end_pos: usize, 40 } 41 42 impl SnippetProvider { span_to_snippet(&self, span: Span) -> Option<&str>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]) 47 } 48 new(start_pos: BytePos, end_pos: BytePos, big_snippet: Lrc<String>) -> Self49 pub(crate) fn new(start_pos: BytePos, end_pos: BytePos, big_snippet: Lrc<String>) -> Self { 50 let start_pos = start_pos.to_usize(); 51 let end_pos = end_pos.to_usize(); 52 SnippetProvider { 53 big_snippet, 54 start_pos, 55 end_pos, 56 } 57 } 58 entire_snippet(&self) -> &str59 pub(crate) fn entire_snippet(&self) -> &str { 60 self.big_snippet.as_str() 61 } 62 start_pos(&self) -> BytePos63 pub(crate) fn start_pos(&self) -> BytePos { 64 BytePos::from_usize(self.start_pos) 65 } 66 end_pos(&self) -> BytePos67 pub(crate) fn end_pos(&self) -> BytePos { 68 BytePos::from_usize(self.end_pos) 69 } 70 } 71 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, 90 } 91 92 impl<'a> Drop for FmtVisitor<'a> { drop(&mut self)93 fn drop(&mut self) { 94 if let Some(ctx) = self.parent_context { 95 if self.macro_rewrite_failure { 96 ctx.macro_rewrite_failure.replace(true); 97 } 98 } 99 } 100 } 101 102 impl<'b, 'a: 'b> FmtVisitor<'a> { set_parent_context(&mut self, context: &'a RewriteContext<'_>)103 fn set_parent_context(&mut self, context: &'a RewriteContext<'_>) { 104 self.parent_context = Some(context); 105 } 106 shape(&self) -> Shape107 pub(crate) fn shape(&self) -> Shape { 108 Shape::indented(self.block_indent, self.config) 109 } 110 next_span(&self, hi: BytePos) -> Span111 fn next_span(&self, hi: BytePos) -> Span { 112 mk_sp(self.last_pos, hi) 113 } 114 visit_stmt(&mut self, stmt: &Stmt<'_>, include_empty_semi: bool)115 fn visit_stmt(&mut self, stmt: &Stmt<'_>, include_empty_semi: bool) { 116 debug!( 117 "visit_stmt: {}", 118 self.parse_sess.span_to_debug_info(stmt.span()) 119 ); 120 121 if stmt.is_empty() { 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 126 .find(|c| c != ' ') 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()); 136 } else { 137 if original_starts_with_newline { 138 self.push_str("\n"); 139 } 140 141 self.push_str(&self.block_indent.to_string(self.config)); 142 self.push_str(snippet); 143 } 144 } else if include_empty_semi { 145 self.push_str(";"); 146 } 147 self.last_pos = stmt.span().hi(); 148 return; 149 } 150 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(); 155 } 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( 160 attrs, 161 stmt.span(), 162 get_span_without_attrs(stmt.as_ast_node()), 163 ); 164 } else { 165 let shape = self.shape(); 166 let rewrite = self.with_context(|ctx| stmt.rewrite(ctx, shape)); 167 self.push_rewrite(stmt.span(), rewrite) 168 } 169 } 170 ast::StmtKind::MacCall(ref mac_stmt) => { 171 if self.visit_attrs(&mac_stmt.attrs, ast::AttrStyle::Outer) { 172 self.push_skipped_with_span( 173 &mac_stmt.attrs, 174 stmt.span(), 175 get_span_without_attrs(stmt.as_ast_node()), 176 ); 177 } else { 178 self.visit_mac(&mac_stmt.mac, None, MacroPosition::Statement); 179 } 180 self.format_missing(stmt.span().hi()); 181 } 182 ast::StmtKind::Empty => (), 183 } 184 } 185 186 /// Remove spaces between the opening brace and the first statement or the inner attribute 187 /// of the block. trim_spaces_after_opening_brace( &mut self, b: &ast::Block, inner_attrs: Option<&[ast::Attribute]>, )188 fn trim_spaces_after_opening_brace( 189 &mut self, 190 b: &ast::Block, 191 inner_attrs: Option<&[ast::Attribute]>, 192 ) { 193 if let Some(first_stmt) = b.stmts.first() { 194 let hi = inner_attrs 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) 200 .next() 201 .and_then(|(kind, _, s)| { 202 if kind == CodeCharKind::Normal { 203 s.rfind('\n') 204 } else { 205 None 206 } 207 }); 208 if let Some(len) = len { 209 self.last_pos = self.last_pos + BytePos::from_usize(len); 210 } 211 } 212 } 213 visit_block( &mut self, b: &ast::Block, inner_attrs: Option<&[ast::Attribute]>, has_braces: bool, )214 pub(crate) fn visit_block( 215 &mut self, 216 b: &ast::Block, 217 inner_attrs: Option<&[ast::Attribute]>, 218 has_braces: bool, 219 ) { 220 debug!( 221 "visit_block: {}", 222 self.parse_sess.span_to_debug_info(b.span), 223 ); 224 225 // Check if this block has braces. 226 let brace_compensation = BytePos(if has_braces { 1 } else { 0 }); 227 228 self.last_pos = self.last_pos + brace_compensation; 229 self.block_indent = self.block_indent.block_indent(self.config); 230 self.push_str("{"); 231 self.trim_spaces_after_opening_brace(b, inner_attrs); 232 233 // Format inner attributes if available. 234 if let Some(attrs) = inner_attrs { 235 self.visit_attrs(attrs, ast::AttrStyle::Inner); 236 } 237 238 self.walk_block_stmts(b); 239 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) { 243 self.push_str(";"); 244 } 245 } 246 } 247 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); 252 } else { 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)); 256 } 257 self.last_pos = source!(self, b.span).hi(); 258 } 259 close_block(&mut self, span: Span, unindent_comment: bool)260 fn close_block(&mut self, span: Span, unindent_comment: bool) { 261 let config = self.config; 262 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; 267 268 let skip_normal = |s: &str| { 269 let trimmed = s.trim(); 270 trimmed.is_empty() || trimmed.chars().all(|c| c == ';') 271 }; 272 273 let comment_snippet = self.snippet(span); 274 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) 278 } else { 279 false 280 }; 281 282 for (kind, offset, sub_slice) in CommentCodeSlices::new(comment_snippet) { 283 let sub_slice = transform_missing_snippet(config, sub_slice); 284 285 debug!("close_block: {:?} {:?} {:?}", kind, offset, sub_slice); 286 287 match kind { 288 CodeCharKind::Comment => { 289 if !unindented && unindent_comment && !align_to_right { 290 unindented = true; 291 self.block_indent = self.block_indent.block_unindent(config); 292 } 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'); 296 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 { 300 self.push_str(" "); 301 // put the first line of the comment on the same line as the 302 // block's last line 303 match sub_slice.find('\n') { 304 None => { 305 self.push_str(&sub_slice); 306 } 307 Some(offset) if offset + 1 == sub_slice.len() => { 308 self.push_str(&sub_slice[..offset]); 309 } 310 Some(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)); 314 315 // put the other lines below it, shaping it as needed 316 let other_lines = &sub_slice[offset + 1..]; 317 let comment_str = 318 rewrite_comment(other_lines, false, comment_shape, config); 319 match comment_str { 320 Some(ref s) => self.push_str(s), 321 None => self.push_str(other_lines), 322 } 323 } 324 } 325 } else { 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()); 330 match comment_shape 331 .visual_indent(offset_len) 332 .sub_width(offset_len) 333 { 334 Some(shp) => comment_shape = shp, 335 None => comment_on_same_line = false, 336 } 337 }; 338 339 if comment_on_same_line { 340 self.push_str(" "); 341 } else { 342 if count_newlines(snippet_in_between) >= 2 || extra_newline { 343 self.push_str("\n"); 344 } 345 self.push_str(&self.block_indent.to_string_with_newline(config)); 346 } 347 348 let comment_str = rewrite_comment(&sub_slice, false, comment_shape, config); 349 match comment_str { 350 Some(ref s) => self.push_str(s), 351 None => self.push_str(&sub_slice), 352 } 353 } 354 } 355 CodeCharKind::Normal if skip_normal(&sub_slice) => { 356 extra_newline = prev_ends_with_newline && sub_slice.contains('\n'); 357 continue; 358 } 359 CodeCharKind::Normal => { 360 self.push_str(&self.block_indent.to_string_with_newline(config)); 361 self.push_str(sub_slice.trim()); 362 } 363 } 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()); 367 } 368 if unindented { 369 self.block_indent = self.block_indent.block_indent(self.config); 370 } 371 self.block_indent = self.block_indent.block_unindent(self.config); 372 self.push_str(&self.block_indent.to_string_with_newline(config)); 373 self.push_str("}"); 374 } 375 unindent_comment_on_closing_brace(&self, b: &ast::Block) -> bool376 fn unindent_comment_on_closing_brace(&self, b: &ast::Block) -> bool { 377 self.is_if_else_block && !b.stmts.is_empty() 378 } 379 380 // Note that this only gets called for function definitions. Required methods 381 // on traits do not get handled here. visit_fn( &mut self, fk: visit::FnKind<'_>, fd: &ast::FnDecl, s: Span, defaultness: ast::Defaultness, inner_attrs: Option<&[ast::Attribute]>, )382 pub(crate) fn visit_fn( 383 &mut self, 384 fk: visit::FnKind<'_>, 385 fd: &ast::FnDecl, 386 s: Span, 387 defaultness: ast::Defaultness, 388 inner_attrs: Option<&[ast::Attribute]>, 389 ) { 390 let indent = self.block_indent; 391 let block; 392 let rewrite = match fk { 393 visit::FnKind::Fn(_, ident, _, _, _, Some(ref b)) => { 394 block = b; 395 self.rewrite_fn_before_block( 396 indent, 397 ident, 398 &FnSig::from_fn_kind(&fk, fd, defaultness), 399 mk_sp(s.lo(), b.span.lo()), 400 ) 401 } 402 _ => unreachable!(), 403 }; 404 405 if let Some((fn_str, fn_brace_style)) = rewrite { 406 self.format_missing_with_indent(source!(self, s).lo()); 407 408 if let Some(rw) = self.single_line_fn(&fn_str, block, inner_attrs) { 409 self.push_str(&rw); 410 self.last_pos = s.hi(); 411 return; 412 } 413 414 self.push_str(&fn_str); 415 match fn_brace_style { 416 FnBraceStyle::SameLine => self.push_str(" "), 417 FnBraceStyle::NextLine => { 418 self.push_str(&self.block_indent.to_string_with_newline(self.config)) 419 } 420 _ => unreachable!(), 421 } 422 self.last_pos = source!(self, block.span).lo(); 423 } else { 424 self.format_missing(source!(self, block.span).lo()); 425 } 426 427 self.visit_block(block, inner_attrs, true) 428 } 429 visit_item(&mut self, item: &ast::Item)430 pub(crate) fn visit_item(&mut self, item: &ast::Item) { 431 skip_out_of_file_lines_range_visitor!(self, item.span); 432 433 // This is where we bail out if there is a skip attribute. This is only 434 // complex in the module case. It is complex because the module could be 435 // in a separate file and there might be attributes in both files, but 436 // the AST lumps them all together. 437 let filtered_attrs; 438 let mut attrs = &item.attrs; 439 let skip_context_saved = self.skip_context.clone(); 440 self.skip_context.update_with_attrs(attrs); 441 442 let should_visit_node_again = match item.kind { 443 // For use/extern crate items, skip rewriting attributes but check for a skip attribute. 444 ast::ItemKind::Use(..) | ast::ItemKind::ExternCrate(_) => { 445 if contains_skip(attrs) { 446 self.push_skipped_with_span(attrs.as_slice(), item.span(), item.span()); 447 false 448 } else { 449 true 450 } 451 } 452 // Module is inline, in this case we treat it like any other item. 453 _ if !is_mod_decl(item) => { 454 if self.visit_attrs(&item.attrs, ast::AttrStyle::Outer) { 455 self.push_skipped_with_span(item.attrs.as_slice(), item.span(), item.span()); 456 false 457 } else { 458 true 459 } 460 } 461 // Module is not inline, but should be skipped. 462 ast::ItemKind::Mod(..) if contains_skip(&item.attrs) => false, 463 // Module is not inline and should not be skipped. We want 464 // to process only the attributes in the current file. 465 ast::ItemKind::Mod(..) => { 466 filtered_attrs = filter_inline_attrs(&item.attrs, item.span()); 467 // Assert because if we should skip it should be caught by 468 // the above case. 469 assert!(!self.visit_attrs(&filtered_attrs, ast::AttrStyle::Outer)); 470 attrs = &filtered_attrs; 471 true 472 } 473 _ => { 474 if self.visit_attrs(&item.attrs, ast::AttrStyle::Outer) { 475 self.push_skipped_with_span(item.attrs.as_slice(), item.span(), item.span()); 476 false 477 } else { 478 true 479 } 480 } 481 }; 482 483 // TODO(calebcartwright): consider enabling box_patterns feature gate 484 if should_visit_node_again { 485 match item.kind { 486 ast::ItemKind::Use(ref tree) => self.format_import(item, tree), 487 ast::ItemKind::Impl(ref iimpl) => { 488 let block_indent = self.block_indent; 489 let rw = self.with_context(|ctx| format_impl(ctx, item, iimpl, block_indent)); 490 self.push_rewrite(item.span, rw); 491 } 492 ast::ItemKind::Trait(..) => { 493 let block_indent = self.block_indent; 494 let rw = self.with_context(|ctx| format_trait(ctx, item, block_indent)); 495 self.push_rewrite(item.span, rw); 496 } 497 ast::ItemKind::TraitAlias(ref generics, ref generic_bounds) => { 498 let shape = Shape::indented(self.block_indent, self.config); 499 let rw = format_trait_alias( 500 &self.get_context(), 501 item.ident, 502 &item.vis, 503 generics, 504 generic_bounds, 505 shape, 506 ); 507 self.push_rewrite(item.span, rw); 508 } 509 ast::ItemKind::ExternCrate(_) => { 510 let rw = rewrite_extern_crate(&self.get_context(), item, self.shape()); 511 let span = if attrs.is_empty() { 512 item.span 513 } else { 514 mk_sp(attrs[0].span.lo(), item.span.hi()) 515 }; 516 self.push_rewrite(span, rw); 517 } 518 ast::ItemKind::Struct(..) | ast::ItemKind::Union(..) => { 519 self.visit_struct(&StructParts::from_item(item)); 520 } 521 ast::ItemKind::Enum(ref def, ref generics) => { 522 self.format_missing_with_indent(source!(self, item.span).lo()); 523 self.visit_enum(item.ident, &item.vis, def, generics, item.span); 524 self.last_pos = source!(self, item.span).hi(); 525 } 526 ast::ItemKind::Mod(unsafety, ref mod_kind) => { 527 self.format_missing_with_indent(source!(self, item.span).lo()); 528 self.format_mod(mod_kind, unsafety, &item.vis, item.span, item.ident, attrs); 529 } 530 ast::ItemKind::MacCall(ref mac) => { 531 self.visit_mac(mac, Some(item.ident), MacroPosition::Item); 532 } 533 ast::ItemKind::ForeignMod(ref foreign_mod) => { 534 self.format_missing_with_indent(source!(self, item.span).lo()); 535 self.format_foreign_mod(foreign_mod, item.span); 536 } 537 ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => { 538 self.visit_static(&StaticParts::from_item(item)); 539 } 540 ast::ItemKind::Fn(ref fn_kind) => { 541 let ast::Fn { 542 defaultness, 543 ref sig, 544 ref generics, 545 ref body, 546 } = **fn_kind; 547 if let Some(ref body) = body { 548 let inner_attrs = inner_attributes(&item.attrs); 549 let fn_ctxt = match sig.header.ext { 550 ast::Extern::None => visit::FnCtxt::Free, 551 _ => visit::FnCtxt::Foreign, 552 }; 553 self.visit_fn( 554 visit::FnKind::Fn( 555 fn_ctxt, 556 item.ident, 557 sig, 558 &item.vis, 559 generics, 560 Some(body), 561 ), 562 &sig.decl, 563 item.span, 564 defaultness, 565 Some(&inner_attrs), 566 ) 567 } else { 568 let indent = self.block_indent; 569 let rewrite = self.rewrite_required_fn( 570 indent, item.ident, sig, &item.vis, generics, item.span, 571 ); 572 self.push_rewrite(item.span, rewrite); 573 } 574 } 575 ast::ItemKind::TyAlias(ref ty_alias) => { 576 use ItemVisitorKind::Item; 577 self.visit_ty_alias_kind(ty_alias, &Item(item), item.span); 578 } 579 ast::ItemKind::GlobalAsm(..) => { 580 let snippet = Some(self.snippet(item.span).to_owned()); 581 self.push_rewrite(item.span, snippet); 582 } 583 ast::ItemKind::MacroDef(ref def) => { 584 let rewrite = rewrite_macro_def( 585 &self.get_context(), 586 self.shape(), 587 self.block_indent, 588 def, 589 item.ident, 590 &item.vis, 591 item.span, 592 ); 593 self.push_rewrite(item.span, rewrite); 594 } 595 }; 596 } 597 self.skip_context = skip_context_saved; 598 } 599 visit_ty_alias_kind( &mut self, ty_kind: &ast::TyAlias, visitor_kind: &ItemVisitorKind<'_>, span: Span, )600 fn visit_ty_alias_kind( 601 &mut self, 602 ty_kind: &ast::TyAlias, 603 visitor_kind: &ItemVisitorKind<'_>, 604 span: Span, 605 ) { 606 let rewrite = rewrite_type_alias( 607 ty_kind, 608 &self.get_context(), 609 self.block_indent, 610 visitor_kind, 611 span, 612 ); 613 self.push_rewrite(span, rewrite); 614 } 615 visit_assoc_item(&mut self, visitor_kind: &ItemVisitorKind<'_>)616 fn visit_assoc_item(&mut self, visitor_kind: &ItemVisitorKind<'_>) { 617 use ItemVisitorKind::*; 618 // TODO(calebcartwright): Not sure the skip spans are correct 619 let (ai, skip_span, assoc_ctxt) = match visitor_kind { 620 AssocTraitItem(ai) => (*ai, ai.span(), visit::AssocCtxt::Trait), 621 AssocImplItem(ai) => (*ai, ai.span, visit::AssocCtxt::Impl), 622 _ => unreachable!(), 623 }; 624 skip_out_of_file_lines_range_visitor!(self, ai.span); 625 626 if self.visit_attrs(&ai.attrs, ast::AttrStyle::Outer) { 627 self.push_skipped_with_span(ai.attrs.as_slice(), skip_span, skip_span); 628 return; 629 } 630 631 // TODO(calebcartwright): consider enabling box_patterns feature gate 632 match (&ai.kind, visitor_kind) { 633 (ast::AssocItemKind::Const(..), AssocTraitItem(_)) => { 634 self.visit_static(&StaticParts::from_trait_item(ai)) 635 } 636 (ast::AssocItemKind::Const(..), AssocImplItem(_)) => { 637 self.visit_static(&StaticParts::from_impl_item(ai)) 638 } 639 (ast::AssocItemKind::Fn(ref fn_kind), _) => { 640 let ast::Fn { 641 defaultness, 642 ref sig, 643 ref generics, 644 ref body, 645 } = **fn_kind; 646 if let Some(ref body) = body { 647 let inner_attrs = inner_attributes(&ai.attrs); 648 let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt); 649 self.visit_fn( 650 visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, Some(body)), 651 &sig.decl, 652 ai.span, 653 defaultness, 654 Some(&inner_attrs), 655 ); 656 } else { 657 let indent = self.block_indent; 658 let rewrite = 659 self.rewrite_required_fn(indent, ai.ident, sig, &ai.vis, generics, ai.span); 660 self.push_rewrite(ai.span, rewrite); 661 } 662 } 663 (ast::AssocItemKind::Type(ref ty_alias), _) => { 664 self.visit_ty_alias_kind(ty_alias, visitor_kind, ai.span); 665 } 666 (ast::AssocItemKind::MacCall(ref mac), _) => { 667 self.visit_mac(mac, Some(ai.ident), MacroPosition::Item); 668 } 669 _ => unreachable!(), 670 } 671 } 672 visit_trait_item(&mut self, ti: &ast::AssocItem)673 pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) { 674 self.visit_assoc_item(&ItemVisitorKind::AssocTraitItem(ti)); 675 } 676 visit_impl_item(&mut self, ii: &ast::AssocItem)677 pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) { 678 self.visit_assoc_item(&ItemVisitorKind::AssocImplItem(ii)); 679 } 680 visit_mac(&mut self, mac: &ast::MacCall, ident: Option<symbol::Ident>, pos: MacroPosition)681 fn visit_mac(&mut self, mac: &ast::MacCall, ident: Option<symbol::Ident>, pos: MacroPosition) { 682 skip_out_of_file_lines_range_visitor!(self, mac.span()); 683 684 // 1 = ; 685 let shape = self.shape().saturating_sub_width(1); 686 let rewrite = self.with_context(|ctx| rewrite_macro(mac, ident, ctx, shape, pos)); 687 // As of v638 of the rustc-ap-* crates, the associated span no longer includes 688 // the trailing semicolon. This determines the correct span to ensure scenarios 689 // with whitespace between the delimiters and trailing semi (i.e. `foo!(abc) ;`) 690 // are formatted correctly. 691 let (span, rewrite) = match macro_style(mac, &self.get_context()) { 692 Delimiter::Bracket | Delimiter::Parenthesis if MacroPosition::Item == pos => { 693 let search_span = mk_sp(mac.span().hi(), self.snippet_provider.end_pos()); 694 let hi = self.snippet_provider.span_before(search_span, ";"); 695 let target_span = mk_sp(mac.span().lo(), hi + BytePos(1)); 696 let rewrite = rewrite.map(|rw| { 697 if !rw.ends_with(';') { 698 format!("{};", rw) 699 } else { 700 rw 701 } 702 }); 703 (target_span, rewrite) 704 } 705 _ => (mac.span(), rewrite), 706 }; 707 708 self.push_rewrite(span, rewrite); 709 } 710 push_str(&mut self, s: &str)711 pub(crate) fn push_str(&mut self, s: &str) { 712 self.line_number += count_newlines(s); 713 self.buffer.push_str(s); 714 } 715 716 #[allow(clippy::needless_pass_by_value)] push_rewrite_inner(&mut self, span: Span, rewrite: Option<String>)717 fn push_rewrite_inner(&mut self, span: Span, rewrite: Option<String>) { 718 if let Some(ref s) = rewrite { 719 self.push_str(s); 720 } else { 721 let snippet = self.snippet(span); 722 self.push_str(snippet.trim()); 723 } 724 self.last_pos = source!(self, span).hi(); 725 } 726 push_rewrite(&mut self, span: Span, rewrite: Option<String>)727 pub(crate) fn push_rewrite(&mut self, span: Span, rewrite: Option<String>) { 728 self.format_missing_with_indent(source!(self, span).lo()); 729 self.push_rewrite_inner(span, rewrite); 730 } 731 push_skipped_with_span( &mut self, attrs: &[ast::Attribute], item_span: Span, main_span: Span, )732 pub(crate) fn push_skipped_with_span( 733 &mut self, 734 attrs: &[ast::Attribute], 735 item_span: Span, 736 main_span: Span, 737 ) { 738 self.format_missing_with_indent(source!(self, item_span).lo()); 739 // do not take into account the lines with attributes as part of the skipped range 740 let attrs_end = attrs 741 .iter() 742 .map(|attr| self.parse_sess.line_of_byte_pos(attr.span.hi())) 743 .max() 744 .unwrap_or(1); 745 let first_line = self.parse_sess.line_of_byte_pos(main_span.lo()); 746 // Statement can start after some newlines and/or spaces 747 // or it can be on the same line as the last attribute. 748 // So here we need to take a minimum between the two. 749 let lo = std::cmp::min(attrs_end + 1, first_line); 750 self.push_rewrite_inner(item_span, None); 751 let hi = self.line_number + 1; 752 self.skipped_range.borrow_mut().push((lo, hi)); 753 } 754 from_context(ctx: &'a RewriteContext<'_>) -> FmtVisitor<'a>755 pub(crate) fn from_context(ctx: &'a RewriteContext<'_>) -> FmtVisitor<'a> { 756 let mut visitor = FmtVisitor::from_parse_sess( 757 ctx.parse_sess, 758 ctx.config, 759 ctx.snippet_provider, 760 ctx.report.clone(), 761 ); 762 visitor.skip_context.update(ctx.skip_context.clone()); 763 visitor.set_parent_context(ctx); 764 visitor 765 } 766 from_parse_sess( parse_session: &'a ParseSess, config: &'a Config, snippet_provider: &'a SnippetProvider, report: FormatReport, ) -> FmtVisitor<'a>767 pub(crate) fn from_parse_sess( 768 parse_session: &'a ParseSess, 769 config: &'a Config, 770 snippet_provider: &'a SnippetProvider, 771 report: FormatReport, 772 ) -> FmtVisitor<'a> { 773 let mut skip_context = SkipContext::default(); 774 let mut macro_names = Vec::new(); 775 for macro_selector in config.skip_macro_invocations().0 { 776 match macro_selector { 777 MacroSelector::Name(name) => macro_names.push(name.to_string()), 778 MacroSelector::All => skip_context.macros.skip_all(), 779 } 780 } 781 skip_context.macros.extend(macro_names); 782 FmtVisitor { 783 parent_context: None, 784 parse_sess: parse_session, 785 buffer: String::with_capacity(snippet_provider.big_snippet.len() * 2), 786 last_pos: BytePos(0), 787 block_indent: Indent::empty(), 788 config, 789 is_if_else_block: false, 790 snippet_provider, 791 line_number: 0, 792 skipped_range: Rc::new(RefCell::new(vec![])), 793 is_macro_def: false, 794 macro_rewrite_failure: false, 795 report, 796 skip_context, 797 } 798 } 799 opt_snippet(&'b self, span: Span) -> Option<&'a str>800 pub(crate) fn opt_snippet(&'b self, span: Span) -> Option<&'a str> { 801 self.snippet_provider.span_to_snippet(span) 802 } 803 snippet(&'b self, span: Span) -> &'a str804 pub(crate) fn snippet(&'b self, span: Span) -> &'a str { 805 self.opt_snippet(span).unwrap() 806 } 807 808 // Returns true if we should skip the following item. visit_attrs(&mut self, attrs: &[ast::Attribute], style: ast::AttrStyle) -> bool809 pub(crate) fn visit_attrs(&mut self, attrs: &[ast::Attribute], style: ast::AttrStyle) -> bool { 810 for attr in attrs { 811 if attr.has_name(depr_skip_annotation()) { 812 let file_name = self.parse_sess.span_to_filename(attr.span); 813 self.report.append( 814 file_name, 815 vec![FormattingError::from_span( 816 attr.span, 817 self.parse_sess, 818 ErrorKind::DeprecatedAttr, 819 )], 820 ); 821 } else { 822 match &attr.kind { 823 ast::AttrKind::Normal(ref normal) 824 if self.is_unknown_rustfmt_attr(&normal.item.path.segments) => 825 { 826 let file_name = self.parse_sess.span_to_filename(attr.span); 827 self.report.append( 828 file_name, 829 vec![FormattingError::from_span( 830 attr.span, 831 self.parse_sess, 832 ErrorKind::BadAttr, 833 )], 834 ); 835 } 836 _ => (), 837 } 838 } 839 } 840 if contains_skip(attrs) { 841 return true; 842 } 843 844 let attrs: Vec<_> = attrs.iter().filter(|a| a.style == style).cloned().collect(); 845 if attrs.is_empty() { 846 return false; 847 } 848 849 let rewrite = attrs.rewrite(&self.get_context(), self.shape()); 850 let span = mk_sp(attrs[0].span.lo(), attrs[attrs.len() - 1].span.hi()); 851 self.push_rewrite(span, rewrite); 852 853 false 854 } 855 is_unknown_rustfmt_attr(&self, segments: &[ast::PathSegment]) -> bool856 fn is_unknown_rustfmt_attr(&self, segments: &[ast::PathSegment]) -> bool { 857 if segments[0].ident.to_string() != "rustfmt" { 858 return false; 859 } 860 !is_skip_attr(segments) 861 } 862 walk_mod_items(&mut self, items: &[rustc_ast::ptr::P<ast::Item>])863 fn walk_mod_items(&mut self, items: &[rustc_ast::ptr::P<ast::Item>]) { 864 self.visit_items_with_reordering(&ptr_vec_to_ref_vec(items)); 865 } 866 walk_stmts(&mut self, stmts: &[Stmt<'_>], include_current_empty_semi: bool)867 fn walk_stmts(&mut self, stmts: &[Stmt<'_>], include_current_empty_semi: bool) { 868 if stmts.is_empty() { 869 return; 870 } 871 872 // Extract leading `use ...;`. 873 let items: Vec<_> = stmts 874 .iter() 875 .take_while(|stmt| stmt.to_item().map_or(false, is_use_item)) 876 .filter_map(|stmt| stmt.to_item()) 877 .collect(); 878 879 if items.is_empty() { 880 self.visit_stmt(&stmts[0], include_current_empty_semi); 881 882 // FIXME(calebcartwright 2021-01-03) - This exists strictly to maintain legacy 883 // formatting where rustfmt would preserve redundant semicolons on Items in a 884 // statement position. 885 // 886 // Starting in rustc-ap-* v692 (~2020-12-01) the rustc parser now parses this as 887 // two separate statements (Item and Empty kinds), whereas before it was parsed as 888 // a single statement with the statement's span including the redundant semicolon. 889 // 890 // rustfmt typically tosses unnecessary/redundant semicolons, and eventually we 891 // should toss these as well, but doing so at this time would 892 // break the Stability Guarantee 893 // N.B. This could be updated to utilize the version gates. 894 let include_next_empty = if stmts.len() > 1 { 895 matches!( 896 (&stmts[0].as_ast_node().kind, &stmts[1].as_ast_node().kind), 897 (ast::StmtKind::Item(_), ast::StmtKind::Empty) 898 ) 899 } else { 900 false 901 }; 902 903 self.walk_stmts(&stmts[1..], include_next_empty); 904 } else { 905 self.visit_items_with_reordering(&items); 906 self.walk_stmts(&stmts[items.len()..], false); 907 } 908 } 909 walk_block_stmts(&mut self, b: &ast::Block)910 fn walk_block_stmts(&mut self, b: &ast::Block) { 911 self.walk_stmts(&Stmt::from_ast_nodes(b.stmts.iter()), false) 912 } 913 format_mod( &mut self, mod_kind: &ast::ModKind, unsafety: ast::Unsafe, vis: &ast::Visibility, s: Span, ident: symbol::Ident, attrs: &[ast::Attribute], )914 fn format_mod( 915 &mut self, 916 mod_kind: &ast::ModKind, 917 unsafety: ast::Unsafe, 918 vis: &ast::Visibility, 919 s: Span, 920 ident: symbol::Ident, 921 attrs: &[ast::Attribute], 922 ) { 923 let vis_str = utils::format_visibility(&self.get_context(), vis); 924 self.push_str(&*vis_str); 925 self.push_str(format_unsafety(unsafety)); 926 self.push_str("mod "); 927 // Calling `to_owned()` to work around borrow checker. 928 let ident_str = rewrite_ident(&self.get_context(), ident).to_owned(); 929 self.push_str(&ident_str); 930 931 if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans) = mod_kind { 932 let ast::ModSpans { 933 inner_span, 934 inject_use_span: _, 935 } = *spans; 936 match self.config.brace_style() { 937 BraceStyle::AlwaysNextLine => { 938 let indent_str = self.block_indent.to_string_with_newline(self.config); 939 self.push_str(&indent_str); 940 self.push_str("{"); 941 } 942 _ => self.push_str(" {"), 943 } 944 // Hackery to account for the closing }. 945 let mod_lo = self.snippet_provider.span_after(source!(self, s), "{"); 946 let body_snippet = 947 self.snippet(mk_sp(mod_lo, source!(self, inner_span).hi() - BytePos(1))); 948 let body_snippet = body_snippet.trim(); 949 if body_snippet.is_empty() { 950 self.push_str("}"); 951 } else { 952 self.last_pos = mod_lo; 953 self.block_indent = self.block_indent.block_indent(self.config); 954 self.visit_attrs(attrs, ast::AttrStyle::Inner); 955 self.walk_mod_items(items); 956 let missing_span = self.next_span(inner_span.hi() - BytePos(1)); 957 self.close_block(missing_span, false); 958 } 959 self.last_pos = source!(self, inner_span).hi(); 960 } else { 961 self.push_str(";"); 962 self.last_pos = source!(self, s).hi(); 963 } 964 } 965 format_separate_mod(&mut self, m: &Module<'_>, end_pos: BytePos)966 pub(crate) fn format_separate_mod(&mut self, m: &Module<'_>, end_pos: BytePos) { 967 self.block_indent = Indent::empty(); 968 let skipped = self.visit_attrs(m.attrs(), ast::AttrStyle::Inner); 969 assert!( 970 !skipped, 971 "Skipping module must be handled before reaching this line." 972 ); 973 self.walk_mod_items(&m.items); 974 self.format_missing_with_indent(end_pos); 975 } 976 skip_empty_lines(&mut self, end_pos: BytePos)977 pub(crate) fn skip_empty_lines(&mut self, end_pos: BytePos) { 978 while let Some(pos) = self 979 .snippet_provider 980 .opt_span_after(self.next_span(end_pos), "\n") 981 { 982 if let Some(snippet) = self.opt_snippet(self.next_span(pos)) { 983 if snippet.trim().is_empty() { 984 self.last_pos = pos; 985 } else { 986 return; 987 } 988 } 989 } 990 } 991 with_context<F>(&mut self, f: F) -> Option<String> where F: Fn(&RewriteContext<'_>) -> Option<String>,992 pub(crate) fn with_context<F>(&mut self, f: F) -> Option<String> 993 where 994 F: Fn(&RewriteContext<'_>) -> Option<String>, 995 { 996 let context = self.get_context(); 997 let result = f(&context); 998 999 self.macro_rewrite_failure |= context.macro_rewrite_failure.get(); 1000 result 1001 } 1002 get_context(&self) -> RewriteContext<'_>1003 pub(crate) fn get_context(&self) -> RewriteContext<'_> { 1004 RewriteContext { 1005 parse_sess: self.parse_sess, 1006 config: self.config, 1007 inside_macro: Rc::new(Cell::new(false)), 1008 use_block: Cell::new(false), 1009 is_if_else_block: Cell::new(false), 1010 force_one_line_chain: Cell::new(false), 1011 snippet_provider: self.snippet_provider, 1012 macro_rewrite_failure: Cell::new(false), 1013 is_macro_def: self.is_macro_def, 1014 report: self.report.clone(), 1015 skip_context: self.skip_context.clone(), 1016 skipped_range: self.skipped_range.clone(), 1017 } 1018 } 1019 } 1020