X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fvisitor.rs;h=fefeffac95c8fc416a510e215e7f6a2ff8664f65;hb=b7c38c9d50fcf48e40cf245b48ab9f36054f40d3;hp=c6ae3b3be1e866cd332b2f58d6e6a8d6ef36c672;hpb=9f53665f91be16c9aa7afd83f7c79357fec9152b;p=rust.git diff --git a/src/visitor.rs b/src/visitor.rs index c6ae3b3be1e..fefeffac95c 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -1,56 +1,52 @@ use std::cell::{Cell, RefCell}; use std::rc::Rc; -use rustc_session::parse::ParseSess; -use rustc_span::{ - source_map::{self, SourceMap}, - BytePos, Pos, Span, -}; -use syntax::token::DelimToken; -use syntax::{ast, visit}; +use rustc_ast::{ast, attr::HasAttrs, token::DelimToken, visit}; +use rustc_span::{symbol, BytePos, Pos, Span, DUMMY_SP}; use crate::attr::*; -use crate::comment::{rewrite_comment, CodeCharKind, CommentCodeSlices}; +use crate::comment::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices}; use crate::config::Version; use crate::config::{BraceStyle, Config}; use crate::coverage::transform_missing_snippet; use crate::items::{ format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, - rewrite_associated_impl_type, rewrite_associated_type, rewrite_extern_crate, - rewrite_opaque_impl_type, rewrite_opaque_type, rewrite_type_alias, FnBraceStyle, FnSig, - StaticParts, StructParts, + rewrite_associated_impl_type, rewrite_extern_crate, rewrite_opaque_impl_type, + rewrite_opaque_type, rewrite_type_alias, FnBraceStyle, FnSig, StaticParts, StructParts, }; use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition}; +use crate::modules::Module; use crate::rewrite::{Rewrite, RewriteContext}; use crate::shape::{Indent, Shape}; use crate::skip::{is_skip_attr, SkipContext}; use crate::source_map::{LineRangeUtils, SpanUtils}; use crate::spanned::Spanned; use crate::stmt::Stmt; +use crate::syntux::session::ParseSess; use crate::utils::{ - self, contains_skip, count_newlines, depr_skip_annotation, inner_attributes, last_line_width, - mk_sp, ptr_vec_to_ref_vec, rewrite_ident, stmt_expr, + self, contains_skip, count_newlines, depr_skip_annotation, format_unsafety, inner_attributes, + last_line_width, mk_sp, ptr_vec_to_ref_vec, rewrite_ident, starts_with_newline, stmt_expr, }; use crate::{ErrorKind, FormatReport, FormattingError}; /// Creates a string slice corresponding to the specified span. -pub(crate) struct SnippetProvider<'a> { +pub(crate) struct SnippetProvider { /// A pointer to the content of the file we are formatting. - big_snippet: &'a str, + big_snippet: Rc, /// A position of the start of `big_snippet`, used as an offset. start_pos: usize, /// A end position of the file that this snippet lives. end_pos: usize, } -impl<'a> SnippetProvider<'a> { +impl SnippetProvider { pub(crate) fn span_to_snippet(&self, span: Span) -> Option<&str> { let start_index = span.lo().to_usize().checked_sub(self.start_pos)?; let end_index = span.hi().to_usize().checked_sub(self.start_pos)?; Some(&self.big_snippet[start_index..end_index]) } - pub(crate) fn new(start_pos: BytePos, end_pos: BytePos, big_snippet: &'a str) -> Self { + pub(crate) fn new(start_pos: BytePos, end_pos: BytePos, big_snippet: Rc) -> Self { let start_pos = start_pos.to_usize(); let end_pos = end_pos.to_usize(); SnippetProvider { @@ -60,6 +56,14 @@ pub(crate) fn new(start_pos: BytePos, end_pos: BytePos, big_snippet: &'a str) -> } } + pub(crate) fn entire_snippet(&self) -> &str { + self.big_snippet.as_str() + } + + pub(crate) fn start_pos(&self) -> BytePos { + BytePos::from_usize(self.start_pos) + } + pub(crate) fn end_pos(&self) -> BytePos { BytePos::from_usize(self.end_pos) } @@ -67,15 +71,14 @@ pub(crate) fn end_pos(&self) -> BytePos { pub(crate) struct FmtVisitor<'a> { parent_context: Option<&'a RewriteContext<'a>>, - pub(crate) parse_session: &'a ParseSess, - pub(crate) source_map: &'a SourceMap, + pub(crate) parse_sess: &'a ParseSess, pub(crate) buffer: String, pub(crate) last_pos: BytePos, // FIXME: use an RAII util or closure for indenting pub(crate) block_indent: Indent, pub(crate) config: &'a Config, pub(crate) is_if_else_block: bool, - pub(crate) snippet_provider: &'a SnippetProvider<'a>, + pub(crate) snippet_provider: &'a SnippetProvider, pub(crate) line_number: usize, /// List of 1-based line ranges which were annotated with skip /// Both bounds are inclusifs. @@ -83,6 +86,7 @@ pub(crate) struct FmtVisitor<'a> { pub(crate) macro_rewrite_failure: bool, pub(crate) report: FormatReport, pub(crate) skip_context: SkipContext, + pub(crate) is_macro_def: bool, } impl<'a> Drop for FmtVisitor<'a> { @@ -110,16 +114,26 @@ fn next_span(&self, hi: BytePos) -> Span { fn visit_stmt(&mut self, stmt: &Stmt<'_>) { debug!( - "visit_stmt: {:?} {:?} `{}`", - self.source_map.lookup_char_pos(stmt.span().lo()), - self.source_map.lookup_char_pos(stmt.span().hi()), - self.snippet(stmt.span()), + "visit_stmt: {}", + self.parse_sess.span_to_debug_info(stmt.span()) ); - // https://github.com/rust-lang/rust/issues/63679. - let is_all_semicolons = - |snippet: &str| snippet.chars().all(|c| c.is_whitespace() || c == ';'); - if is_all_semicolons(&self.snippet(stmt.span())) { + if stmt.is_empty() { + // If the statement is empty, just skip over it. Before that, make sure any comment + // snippet preceding the semicolon is picked up. + let snippet = self.snippet(mk_sp(self.last_pos, stmt.span().lo())); + let original_starts_with_newline = snippet + .find(|c| c != ' ') + .map_or(false, |i| starts_with_newline(&snippet[i..])); + let snippet = snippet.trim(); + if !snippet.is_empty() { + if original_starts_with_newline { + self.push_str("\n"); + } + self.push_str(&self.block_indent.to_string(self.config)); + self.push_str(snippet); + } + self.last_pos = stmt.span().hi(); return; } @@ -144,19 +158,19 @@ fn visit_stmt(&mut self, stmt: &Stmt<'_>) { self.push_rewrite(stmt.span(), rewrite) } } - ast::StmtKind::Mac(ref mac) => { - let (ref mac, _macro_style, ref attrs) = **mac; - if self.visit_attrs(attrs, ast::AttrStyle::Outer) { + ast::StmtKind::MacCall(ref mac_stmt) => { + if self.visit_attrs(&mac_stmt.attrs, ast::AttrStyle::Outer) { self.push_skipped_with_span( - attrs, + &mac_stmt.attrs, stmt.span(), get_span_without_attrs(stmt.as_ast_node()), ); } else { - self.visit_mac(mac, None, MacroPosition::Statement); + self.visit_mac(&mac_stmt.mac, None, MacroPosition::Statement); } self.format_missing(stmt.span().hi()); } + ast::StmtKind::Empty => (), } } @@ -195,9 +209,8 @@ pub(crate) fn visit_block( has_braces: bool, ) { debug!( - "visit_block: {:?} {:?}", - self.source_map.lookup_char_pos(b.span.lo()), - self.source_map.lookup_char_pos(b.span.hi()) + "visit_block: {}", + self.parse_sess.span_to_debug_info(b.span), ); // Check if this block has braces. @@ -248,14 +261,23 @@ fn close_block(&mut self, span: Span, unindent_comment: bool) { trimmed.is_empty() || trimmed.chars().all(|c| c == ';') }; - for (kind, offset, sub_slice) in CommentCodeSlices::new(self.snippet(span)) { + let comment_snippet = self.snippet(span); + + let align_to_right = if unindent_comment && contains_comment(&comment_snippet) { + let first_lines = comment_snippet.splitn(2, '/').next().unwrap_or(""); + last_line_width(first_lines) > last_line_width(&comment_snippet) + } else { + false + }; + + for (kind, offset, sub_slice) in CommentCodeSlices::new(comment_snippet) { let sub_slice = transform_missing_snippet(config, sub_slice); debug!("close_block: {:?} {:?} {:?}", kind, offset, sub_slice); match kind { CodeCharKind::Comment => { - if !unindented && unindent_comment { + if !unindented && unindent_comment && !align_to_right { unindented = true; self.block_indent = self.block_indent.block_unindent(config); } @@ -348,7 +370,7 @@ fn unindent_comment_on_closing_brace(&self, b: &ast::Block) -> bool { // Note that this only gets called for function definitions. Required methods // on traits do not get handled here. - fn visit_fn( + pub(crate) fn visit_fn( &mut self, fk: visit::FnKind<'_>, generics: &ast::Generics, @@ -497,7 +519,7 @@ pub(crate) fn visit_item(&mut self, item: &ast::Item) { self.format_missing_with_indent(source!(self, item.span).lo()); self.format_mod(module, &item.vis, item.span, item.ident, attrs, is_inline); } - ast::ItemKind::Mac(ref mac) => { + ast::ItemKind::MacCall(ref mac) => { self.visit_mac(mac, Some(item.ident), MacroPosition::Item); } ast::ItemKind::ForeignMod(ref foreign_mod) => { @@ -507,7 +529,7 @@ pub(crate) fn visit_item(&mut self, item: &ast::Item) { ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => { self.visit_static(&StaticParts::from_item(item)); } - ast::ItemKind::Fn(ref fn_signature, ref generics, ref body) => { + ast::ItemKind::Fn(defaultness, ref fn_signature, ref generics, Some(ref body)) => { let inner_attrs = inner_attributes(&item.attrs); let fn_ctxt = match fn_signature.header.ext { ast::Extern::None => visit::FnCtxt::Free, @@ -519,28 +541,42 @@ pub(crate) fn visit_item(&mut self, item: &ast::Item) { item.ident, &fn_signature, &item.vis, - body.as_deref(), + Some(body), ), generics, &fn_signature.decl, item.span, - ast::Defaultness::Final, + defaultness, Some(&inner_attrs), ) } - ast::ItemKind::TyAlias(ref ty, ref generics) => match ty.kind.opaque_top_hack() { - None => { + ast::ItemKind::Fn(_, ref fn_signature, ref generics, None) => { + let indent = self.block_indent; + let rewrite = self.rewrite_required_fn( + indent, + item.ident, + &fn_signature, + generics, + item.span, + ); + + self.push_rewrite(item.span, rewrite); + } + ast::ItemKind::TyAlias(_, ref generics, ref generic_bounds, ref ty) => match ty { + Some(ty) => { let rewrite = rewrite_type_alias( - &self.get_context(), - self.block_indent, item.ident, - ty, + Some(&*ty), generics, + Some(generic_bounds), + &self.get_context(), + self.block_indent, &item.vis, + item.span, ); self.push_rewrite(item.span, rewrite); } - Some(generic_bounds) => { + None => { let rewrite = rewrite_opaque_type( &self.get_context(), self.block_indent, @@ -548,6 +584,7 @@ pub(crate) fn visit_item(&mut self, item: &ast::Item) { generic_bounds, generics, &item.vis, + item.span, ); self.push_rewrite(item.span, rewrite); } @@ -583,37 +620,42 @@ pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) { match ti.kind { ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_trait_item(ti)), - ast::AssocItemKind::Fn(ref sig, None) => { + ast::AssocItemKind::Fn(_, ref sig, ref generics, None) => { let indent = self.block_indent; - let rewrite = - self.rewrite_required_fn(indent, ti.ident, sig, &ti.generics, ti.span); + let rewrite = self.rewrite_required_fn(indent, ti.ident, sig, generics, ti.span); self.push_rewrite(ti.span, rewrite); } - ast::AssocItemKind::Fn(ref sig, Some(ref body)) => { + ast::AssocItemKind::Fn(defaultness, ref sig, ref generics, Some(ref body)) => { let inner_attrs = inner_attributes(&ti.attrs); - let vis = rustc_span::source_map::dummy_spanned(ast::VisibilityKind::Inherited); + let vis = ast::Visibility { + kind: ast::VisibilityKind::Inherited, + span: DUMMY_SP, + tokens: None, + }; let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Trait); self.visit_fn( visit::FnKind::Fn(fn_ctxt, ti.ident, sig, &vis, Some(body)), - &ti.generics, + generics, &sig.decl, ti.span, - ast::Defaultness::Final, + defaultness, Some(&inner_attrs), ); } - ast::AssocItemKind::TyAlias(ref generic_bounds, ref type_default) => { - let rewrite = rewrite_associated_type( + ast::AssocItemKind::TyAlias(_, ref generics, ref generic_bounds, ref type_default) => { + let rewrite = rewrite_type_alias( ti.ident, type_default.as_ref(), - &ti.generics, + generics, Some(generic_bounds), &self.get_context(), self.block_indent, + &ti.vis, + ti.span, ); self.push_rewrite(ti.span, rewrite); } - ast::AssocItemKind::Macro(ref mac) => { + ast::AssocItemKind::MacCall(ref mac) => { self.visit_mac(mac, Some(ti.ident), MacroPosition::Item); } } @@ -628,58 +670,59 @@ pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) { } match ii.kind { - ast::AssocItemKind::Fn(ref sig, Some(ref body)) => { + ast::AssocItemKind::Fn(defaultness, ref sig, ref generics, Some(ref body)) => { let inner_attrs = inner_attributes(&ii.attrs); let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Impl); self.visit_fn( visit::FnKind::Fn(fn_ctxt, ii.ident, sig, &ii.vis, Some(body)), - &ii.generics, + generics, &sig.decl, ii.span, - ii.defaultness, + defaultness, Some(&inner_attrs), ); } - ast::AssocItemKind::Fn(ref sig, None) => { + ast::AssocItemKind::Fn(_, ref sig, ref generics, None) => { let indent = self.block_indent; - let rewrite = - self.rewrite_required_fn(indent, ii.ident, sig, &ii.generics, ii.span); + let rewrite = self.rewrite_required_fn(indent, ii.ident, sig, generics, ii.span); self.push_rewrite(ii.span, rewrite); } ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_impl_item(ii)), - ast::AssocItemKind::TyAlias(_, ref ty) => { + ast::AssocItemKind::TyAlias(defaultness, ref generics, _, ref ty) => { let rewrite_associated = || { rewrite_associated_impl_type( ii.ident, - ii.defaultness, + &ii.vis, + defaultness, ty.as_ref(), - &ii.generics, + &generics, &self.get_context(), self.block_indent, + ii.span, ) }; let rewrite = match ty { None => rewrite_associated(), - Some(ty) => match ty.kind.opaque_top_hack() { - Some(generic_bounds) => rewrite_opaque_impl_type( + Some(ty) => match ty.kind { + ast::TyKind::ImplTrait(_, ref bounds) => rewrite_opaque_impl_type( &self.get_context(), ii.ident, - &ii.generics, - generic_bounds, + generics, + bounds, self.block_indent, ), - None => rewrite_associated(), + _ => rewrite_associated(), }, }; self.push_rewrite(ii.span, rewrite); } - ast::AssocItemKind::Macro(ref mac) => { + ast::AssocItemKind::MacCall(ref mac) => { self.visit_mac(mac, Some(ii.ident), MacroPosition::Item); } } } - fn visit_mac(&mut self, mac: &ast::Mac, ident: Option, pos: MacroPosition) { + fn visit_mac(&mut self, mac: &ast::MacCall, ident: Option, pos: MacroPosition) { skip_out_of_file_lines_range_visitor!(self, mac.span()); // 1 = ; @@ -740,10 +783,10 @@ pub(crate) fn push_skipped_with_span( // do not take into account the lines with attributes as part of the skipped range let attrs_end = attrs .iter() - .map(|attr| self.source_map.lookup_char_pos(attr.span.hi()).line) + .map(|attr| self.parse_sess.line_of_byte_pos(attr.span.hi())) .max() .unwrap_or(1); - let first_line = self.source_map.lookup_char_pos(main_span.lo()).line; + let first_line = self.parse_sess.line_of_byte_pos(main_span.lo()); // Statement can start after some newlines and/or spaces // or it can be on the same line as the last attribute. // So here we need to take a minimum between the two. @@ -754,8 +797,8 @@ pub(crate) fn push_skipped_with_span( } pub(crate) fn from_context(ctx: &'a RewriteContext<'_>) -> FmtVisitor<'a> { - let mut visitor = FmtVisitor::from_source_map( - ctx.parse_session, + let mut visitor = FmtVisitor::from_parse_sess( + ctx.parse_sess, ctx.config, ctx.snippet_provider, ctx.report.clone(), @@ -765,16 +808,15 @@ pub(crate) fn from_context(ctx: &'a RewriteContext<'_>) -> FmtVisitor<'a> { visitor } - pub(crate) fn from_source_map( + pub(crate) fn from_parse_sess( parse_session: &'a ParseSess, config: &'a Config, - snippet_provider: &'a SnippetProvider<'_>, + snippet_provider: &'a SnippetProvider, report: FormatReport, ) -> FmtVisitor<'a> { FmtVisitor { parent_context: None, - parse_session, - source_map: parse_session.source_map(), + parse_sess: parse_session, buffer: String::with_capacity(snippet_provider.big_snippet.len() * 2), last_pos: BytePos(0), block_indent: Indent::empty(), @@ -783,6 +825,7 @@ pub(crate) fn from_source_map( snippet_provider, line_number: 0, skipped_range: Rc::new(RefCell::new(vec![])), + is_macro_def: false, macro_rewrite_failure: false, report, skip_context: Default::default(), @@ -800,27 +843,27 @@ pub(crate) fn snippet(&'b self, span: Span) -> &'a str { // Returns true if we should skip the following item. pub(crate) fn visit_attrs(&mut self, attrs: &[ast::Attribute], style: ast::AttrStyle) -> bool { for attr in attrs { - if attr.check_name(depr_skip_annotation()) { - let file_name = self.source_map.span_to_filename(attr.span).into(); + if attr.has_name(depr_skip_annotation()) { + let file_name = self.parse_sess.span_to_filename(attr.span); self.report.append( file_name, vec![FormattingError::from_span( attr.span, - &self.source_map, + self.parse_sess, ErrorKind::DeprecatedAttr, )], ); } else { match &attr.kind { - ast::AttrKind::Normal(ref attribute_item) + ast::AttrKind::Normal(ref attribute_item, _) if self.is_unknown_rustfmt_attr(&attribute_item.path.segments) => { - let file_name = self.source_map.span_to_filename(attr.span).into(); + let file_name = self.parse_sess.span_to_filename(attr.span); self.report.append( file_name, vec![FormattingError::from_span( attr.span, - self.source_map, + self.parse_sess, ErrorKind::BadAttr, )], ); @@ -886,12 +929,13 @@ fn format_mod( m: &ast::Mod, vis: &ast::Visibility, s: Span, - ident: ast::Ident, + ident: symbol::Ident, attrs: &[ast::Attribute], is_internal: bool, ) { let vis_str = utils::format_visibility(&self.get_context(), vis); self.push_str(&*vis_str); + self.push_str(format_unsafety(m.unsafety)); self.push_str("mod "); // Calling `to_owned()` to work around borrow checker. let ident_str = rewrite_ident(&self.get_context(), ident).to_owned(); @@ -928,14 +972,14 @@ fn format_mod( } } - pub(crate) fn format_separate_mod( - &mut self, - m: &ast::Mod, - source_file: &source_map::SourceFile, - ) { + pub(crate) fn format_separate_mod(&mut self, m: &Module<'_>, end_pos: BytePos) { self.block_indent = Indent::empty(); - self.walk_mod_items(m); - self.format_missing_with_indent(source_file.end_pos); + if self.visit_attrs(m.attrs(), ast::AttrStyle::Inner) { + self.push_skipped_with_span(m.attrs(), m.as_ref().inner, m.as_ref().inner); + } else { + self.walk_mod_items(m.as_ref()); + self.format_missing_with_indent(end_pos); + } } pub(crate) fn skip_empty_lines(&mut self, end_pos: BytePos) { @@ -966,8 +1010,7 @@ pub(crate) fn with_context(&mut self, f: F) -> Option pub(crate) fn get_context(&self) -> RewriteContext<'_> { RewriteContext { - parse_session: self.parse_session, - source_map: self.source_map, + parse_sess: self.parse_sess, config: self.config, inside_macro: Rc::new(Cell::new(false)), use_block: Cell::new(false), @@ -975,6 +1018,7 @@ pub(crate) fn get_context(&self) -> RewriteContext<'_> { force_one_line_chain: Cell::new(false), snippet_provider: self.snippet_provider, macro_rewrite_failure: Cell::new(false), + is_macro_def: self.is_macro_def, report: self.report.clone(), skip_context: self.skip_context.clone(), skipped_range: self.skipped_range.clone(),