X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fvisitor.rs;h=63e2c6bdcac57c88c8128682b20880aaa8975a67;hb=6fb188bd43840f4a99c6a4b4cdbdb21ccf3304e7;hp=f1b50e19b610fa8e2a8af6cac9e46b7978c751b3;hpb=f5ebcd922e2ef64ea6df17fa86e921304c88ca3c;p=rust.git diff --git a/src/visitor.rs b/src/visitor.rs index f1b50e19b61..63e2c6bdcac 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -8,23 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::{ast, visit}; use syntax::attr::HasAttrs; -use syntax::codemap::{self, BytePos, CodeMap, Pos, Span}; use syntax::parse::ParseSess; +use syntax::source_map::{self, BytePos, Pos, SourceMap, Span}; +use syntax::{ast, visit}; use attr::*; -use codemap::{LineRangeUtils, SpanUtils}; use comment::{CodeCharKind, CommentCodeSlices, FindUncommented}; use config::{BraceStyle, Config}; -use 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_type_alias, FnSig, StaticParts, StructParts}; +use items::{ + format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, + rewrite_associated_impl_type, rewrite_associated_type, rewrite_existential_impl_type, + rewrite_existential_type, rewrite_extern_crate, rewrite_type_alias, FnSig, StaticParts, + StructParts, +}; use macros::{rewrite_macro, rewrite_macro_def, MacroPosition}; use rewrite::{Rewrite, RewriteContext}; use shape::{Indent, Shape}; +use source_map::{LineRangeUtils, SpanUtils}; use spanned::Spanned; -use utils::{self, contains_skip, count_newlines, inner_attributes, mk_sp, ptr_vec_to_ref_vec}; +use utils::{ + self, contains_skip, count_newlines, inner_attributes, mk_sp, ptr_vec_to_ref_vec, + rewrite_ident, DEPR_SKIP_ANNOTATION, +}; +use {ErrorKind, FormatReport, FormattingError}; use std::cell::RefCell; @@ -53,8 +60,9 @@ pub fn new(start_pos: BytePos, big_snippet: &'a str) -> Self { } pub struct FmtVisitor<'a> { + parent_context: Option<&'a RewriteContext<'a>>, pub parse_session: &'a ParseSess, - pub codemap: &'a CodeMap, + pub source_map: &'a SourceMap, pub buffer: String, pub last_pos: BytePos, // FIXME: use an RAII util or closure for indenting @@ -64,9 +72,25 @@ pub struct FmtVisitor<'a> { pub snippet_provider: &'a SnippetProvider<'a>, pub line_number: usize, pub skipped_range: Vec<(usize, usize)>, + pub macro_rewrite_failure: bool, + pub(crate) report: FormatReport, +} + +impl<'a> Drop for FmtVisitor<'a> { + fn drop(&mut self) { + if let Some(ctx) = self.parent_context { + if self.macro_rewrite_failure { + ctx.macro_rewrite_failure.replace(true); + } + } + } } impl<'b, 'a: 'b> FmtVisitor<'a> { + fn set_parent_context(&mut self, context: &'a RewriteContext) { + self.parent_context = Some(context); + } + pub fn shape(&self) -> Shape { Shape::indented(self.block_indent, self.config) } @@ -74,19 +98,22 @@ pub fn shape(&self) -> Shape { fn visit_stmt(&mut self, stmt: &ast::Stmt) { debug!( "visit_stmt: {:?} {:?}", - self.codemap.lookup_char_pos(stmt.span.lo()), - self.codemap.lookup_char_pos(stmt.span.hi()) + self.source_map.lookup_char_pos(stmt.span.lo()), + self.source_map.lookup_char_pos(stmt.span.hi()) ); match stmt.node { ast::StmtKind::Item(ref item) => { self.visit_item(item); + // Handle potential `;` after the item. + self.format_missing(stmt.span.hi()); } ast::StmtKind::Local(..) | ast::StmtKind::Expr(..) | ast::StmtKind::Semi(..) => { if contains_skip(get_attrs_from_stmt(stmt)) { self.push_skipped_with_span(stmt.span()); } else { - let rewrite = stmt.rewrite(&self.get_context(), self.shape()); + let shape = self.shape(); + let rewrite = self.with_context(|ctx| stmt.rewrite(&ctx, shape)); self.push_rewrite(stmt.span(), rewrite) } } @@ -110,8 +137,8 @@ pub fn visit_block( ) { debug!( "visit_block: {:?} {:?}", - self.codemap.lookup_char_pos(b.span.lo()), - self.codemap.lookup_char_pos(b.span.hi()) + self.source_map.lookup_char_pos(b.span.lo()), + self.source_map.lookup_char_pos(b.span.hi()) ); // Check if this block has braces. @@ -121,45 +148,44 @@ pub fn visit_block( self.block_indent = self.block_indent.block_indent(self.config); self.push_str("{"); - if self.config.remove_blank_lines_at_start_or_end_of_block() { - if let Some(first_stmt) = b.stmts.first() { - let attr_lo = inner_attrs - .and_then(|attrs| inner_attributes(attrs).first().map(|attr| attr.span.lo())) - .or_else(|| { - // Attributes for an item in a statement position - // do not belong to the statement. (rust-lang/rust#34459) - if let ast::StmtKind::Item(ref item) = first_stmt.node { - item.attrs.first() - } else { - first_stmt.attrs().first() - }.and_then(|attr| { - // Some stmts can have embedded attributes. - // e.g. `match { #![attr] ... }` - let attr_lo = attr.span.lo(); - if attr_lo < first_stmt.span.lo() { - Some(attr_lo) - } else { - None - } - }) - }); - - let snippet = self.snippet(mk_sp( - self.last_pos, - attr_lo.unwrap_or_else(|| first_stmt.span.lo()), - )); - let len = CommentCodeSlices::new(snippet) - .nth(0) - .and_then(|(kind, _, s)| { - if kind == CodeCharKind::Normal { - s.rfind('\n') + if let Some(first_stmt) = b.stmts.first() { + let attr_lo = inner_attrs + .and_then(|attrs| inner_attributes(attrs).first().map(|attr| attr.span.lo())) + .or_else(|| { + // Attributes for an item in a statement position + // do not belong to the statement. (rust-lang/rust#34459) + if let ast::StmtKind::Item(ref item) = first_stmt.node { + item.attrs.first() + } else { + first_stmt.attrs().first() + } + .and_then(|attr| { + // Some stmts can have embedded attributes. + // e.g. `match { #![attr] ... }` + let attr_lo = attr.span.lo(); + if attr_lo < first_stmt.span.lo() { + Some(attr_lo) } else { None } - }); - if let Some(len) = len { - self.last_pos = self.last_pos + BytePos::from_usize(len); - } + }) + }); + + let snippet = self.snippet(mk_sp( + self.last_pos, + attr_lo.unwrap_or_else(|| first_stmt.span.lo()), + )); + let len = CommentCodeSlices::new(snippet) + .nth(0) + .and_then(|(kind, _, s)| { + if kind == CodeCharKind::Normal { + s.rfind('\n') + } else { + None + } + }); + if let Some(len) = len { + self.last_pos = self.last_pos + BytePos::from_usize(len); } } @@ -188,24 +214,22 @@ pub fn visit_block( } let mut remove_len = BytePos(0); - if self.config.remove_blank_lines_at_start_or_end_of_block() { - if let Some(stmt) = b.stmts.last() { - let snippet = self.snippet(mk_sp( - stmt.span.hi(), - source!(self, b.span).hi() - brace_compensation, - )); - let len = CommentCodeSlices::new(snippet) - .last() - .and_then(|(kind, _, s)| { - if kind == CodeCharKind::Normal && s.trim().is_empty() { - Some(s.len()) - } else { - None - } - }); - if let Some(len) = len { - remove_len = BytePos::from_usize(len); - } + if let Some(stmt) = b.stmts.last() { + let snippet = self.snippet(mk_sp( + stmt.span.hi(), + source!(self, b.span).hi() - brace_compensation, + )); + let len = CommentCodeSlices::new(snippet) + .last() + .and_then(|(kind, _, s)| { + if kind == CodeCharKind::Normal && s.trim().is_empty() { + Some(s.len()) + } else { + None + } + }); + if let Some(len) = len { + remove_len = BytePos::from_usize(len); } } @@ -260,7 +284,7 @@ fn visit_fn( let indent = self.block_indent; let block; let rewrite = match fk { - visit::FnKind::ItemFn(ident, _, _, _, _, b) | visit::FnKind::Method(ident, _, _, b) => { + visit::FnKind::ItemFn(ident, _, _, b) | visit::FnKind::Method(ident, _, _, b) => { block = b; self.rewrite_fn( indent, @@ -268,6 +292,7 @@ fn visit_fn( &FnSig::from_fn_kind(&fk, generics, fd, defaultness), mk_sp(s.lo(), b.span.lo()), b, + inner_attrs, ) } visit::FnKind::Closure(_) => unreachable!(), @@ -300,6 +325,13 @@ pub fn visit_item(&mut self, item: &ast::Item) { let filtered_attrs; let mut attrs = &item.attrs; match item.node { + // For use items, skip rewriting attributes. Just check for a skip attribute. + ast::ItemKind::Use(..) => { + if contains_skip(attrs) { + self.push_skipped_with_span(item.span()); + return; + } + } // Module is inline, in this case we treat it like any other item. _ if !is_mod_decl(item) => { if self.visit_attrs(&item.attrs, ast::AttrStyle::Outer) { @@ -334,21 +366,24 @@ pub fn visit_item(&mut self, item: &ast::Item) { let snippet = self.snippet(item.span); let where_span_end = snippet .find_uncommented("{") - .map(|x| (BytePos(x as u32)) + source!(self, item.span).lo()); - let rw = format_impl(&self.get_context(), item, self.block_indent, where_span_end); + .map(|x| BytePos(x as u32) + source!(self, item.span).lo()); + let block_indent = self.block_indent; + let rw = + self.with_context(|ctx| format_impl(&ctx, item, block_indent, where_span_end)); self.push_rewrite(item.span, rw); } ast::ItemKind::Trait(..) => { - let rw = format_trait(&self.get_context(), item, self.block_indent); + let block_indent = self.block_indent; + let rw = self.with_context(|ctx| format_trait(&ctx, item, block_indent)); self.push_rewrite(item.span, rw); } - ast::ItemKind::TraitAlias(ref generics, ref ty_param_bounds) => { + ast::ItemKind::TraitAlias(ref generics, ref generic_bounds) => { let shape = Shape::indented(self.block_indent, self.config); let rw = format_trait_alias( &self.get_context(), item.ident, generics, - ty_param_bounds, + generic_bounds, shape, ); self.push_rewrite(item.span, rw); @@ -380,14 +415,15 @@ pub 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 decl, unsafety, constness, abi, ref generics, ref body) => { + ast::ItemKind::Fn(ref decl, fn_header, ref generics, ref body) => { + let inner_attrs = inner_attributes(&item.attrs); self.visit_fn( - visit::FnKind::ItemFn(item.ident, unsafety, constness, abi, &item.vis, body), + visit::FnKind::ItemFn(item.ident, fn_header, &item.vis, body), generics, decl, item.span, ast::Defaultness::Final, - Some(&item.attrs), + Some(&inner_attrs), ) } ast::ItemKind::Ty(ref ty, ref generics) => { @@ -398,7 +434,17 @@ pub fn visit_item(&mut self, item: &ast::Item) { ty, generics, &item.vis, - item.span, + ); + self.push_rewrite(item.span, rewrite); + } + ast::ItemKind::Existential(ref generic_bounds, ref generics) => { + let rewrite = rewrite_existential_type( + &self.get_context(), + self.block_indent, + item.ident, + generic_bounds, + generics, + &item.vis, ); self.push_rewrite(item.span, rewrite); } @@ -438,20 +484,22 @@ pub fn visit_trait_item(&mut self, ti: &ast::TraitItem) { self.push_rewrite(ti.span, rewrite); } ast::TraitItemKind::Method(ref sig, Some(ref body)) => { + let inner_attrs = inner_attributes(&ti.attrs); self.visit_fn( visit::FnKind::Method(ti.ident, sig, None, body), &ti.generics, &sig.decl, ti.span, ast::Defaultness::Final, - Some(&ti.attrs), + Some(&inner_attrs), ); } - ast::TraitItemKind::Type(ref type_param_bounds, ref type_default) => { + ast::TraitItemKind::Type(ref generic_bounds, ref type_default) => { let rewrite = rewrite_associated_type( ti.ident, type_default.as_ref(), - Some(type_param_bounds), + &ti.generics, + Some(generic_bounds), &self.get_context(), self.block_indent, ); @@ -473,13 +521,14 @@ pub fn visit_impl_item(&mut self, ii: &ast::ImplItem) { match ii.node { ast::ImplItemKind::Method(ref sig, ref body) => { + let inner_attrs = inner_attributes(&ii.attrs); self.visit_fn( visit::FnKind::Method(ii.ident, sig, Some(&ii.vis), body), &ii.generics, &sig.decl, ii.span, ii.defaultness, - Some(&ii.attrs), + Some(&inner_attrs), ); } ast::ImplItemKind::Const(..) => self.visit_static(&StaticParts::from_impl_item(ii)), @@ -488,12 +537,22 @@ pub fn visit_impl_item(&mut self, ii: &ast::ImplItem) { ii.ident, ii.defaultness, Some(ty), - None, + &ii.generics, &self.get_context(), self.block_indent, ); self.push_rewrite(ii.span, rewrite); } + ast::ImplItemKind::Existential(ref generic_bounds) => { + let rewrite = rewrite_existential_impl_type( + &self.get_context(), + ii.ident, + &ii.generics, + generic_bounds, + self.block_indent, + ); + self.push_rewrite(ii.span, rewrite); + } ast::ImplItemKind::Macro(ref mac) => { self.visit_mac(mac, Some(ii.ident), MacroPosition::Item); } @@ -505,7 +564,7 @@ fn visit_mac(&mut self, mac: &ast::Mac, ident: Option, pos: MacroPos // 1 = ; let shape = self.shape().sub_width(1).unwrap(); - let rewrite = rewrite_macro(mac, ident, &self.get_context(), shape, pos); + let rewrite = self.with_context(|ctx| rewrite_macro(mac, ident, ctx, shape, pos)); self.push_rewrite(mac.span, rewrite); } @@ -539,17 +598,26 @@ pub fn push_skipped_with_span(&mut self, span: Span) { } pub fn from_context(ctx: &'a RewriteContext) -> FmtVisitor<'a> { - FmtVisitor::from_codemap(ctx.parse_session, ctx.config, ctx.snippet_provider) + let mut visitor = FmtVisitor::from_source_map( + ctx.parse_session, + ctx.config, + ctx.snippet_provider, + ctx.report.clone(), + ); + visitor.set_parent_context(ctx); + visitor } - pub fn from_codemap( + pub(crate) fn from_source_map( parse_session: &'a ParseSess, config: &'a Config, snippet_provider: &'a SnippetProvider, + report: FormatReport, ) -> FmtVisitor<'a> { FmtVisitor { + parent_context: None, parse_session, - codemap: parse_session.codemap(), + source_map: parse_session.source_map(), buffer: String::with_capacity(snippet_provider.big_snippet.len() * 2), last_pos: BytePos(0), block_indent: Indent::empty(), @@ -558,6 +626,8 @@ pub fn from_codemap( snippet_provider, line_number: 0, skipped_range: vec![], + macro_rewrite_failure: false, + report, } } @@ -571,6 +641,32 @@ pub fn snippet(&'b self, span: Span) -> &'a str { // Returns true if we should skip the following item. pub fn visit_attrs(&mut self, attrs: &[ast::Attribute], style: ast::AttrStyle) -> bool { + for attr in attrs { + if attr.name() == DEPR_SKIP_ANNOTATION { + let file_name = self.source_map.span_to_filename(attr.span).into(); + self.report.append( + file_name, + vec![FormattingError::from_span( + attr.span, + &self.source_map, + ErrorKind::DeprecatedAttr, + )], + ); + } else if attr.path.segments[0].ident.to_string() == "rustfmt" + && (attr.path.segments.len() == 1 + || attr.path.segments[1].ident.to_string() != "skip") + { + let file_name = self.source_map.span_to_filename(attr.span).into(); + self.report.append( + file_name, + vec![FormattingError::from_span( + attr.span, + &self.source_map, + ErrorKind::BadAttr, + )], + ); + } + } if contains_skip(attrs) { return true; } @@ -632,9 +728,12 @@ fn format_mod( attrs: &[ast::Attribute], is_internal: bool, ) { - self.push_str(&*utils::format_visibility(vis)); + let vis_str = utils::format_visibility(&self.get_context(), vis); + self.push_str(&*vis_str); self.push_str("mod "); - self.push_str(&ident.to_string()); + // Calling `to_owned()` to work around borrow checker. + let ident_str = rewrite_ident(&self.get_context(), ident).to_owned(); + self.push_str(&ident_str); if is_internal { match self.config.brace_style() { @@ -667,14 +766,15 @@ fn format_mod( } } - pub fn format_separate_mod(&mut self, m: &ast::Mod, filemap: &codemap::FileMap) { + pub fn format_separate_mod(&mut self, m: &ast::Mod, source_file: &source_map::SourceFile) { self.block_indent = Indent::empty(); self.walk_mod_items(m); - self.format_missing_with_indent(filemap.end_pos); + self.format_missing_with_indent(source_file.end_pos); } pub fn skip_empty_lines(&mut self, end_pos: BytePos) { - while let Some(pos) = self.snippet_provider + while let Some(pos) = self + .snippet_provider .opt_span_after(mk_sp(self.last_pos, end_pos), "\n") { if let Some(snippet) = self.opt_snippet(mk_sp(self.last_pos, pos)) { @@ -687,16 +787,28 @@ pub fn skip_empty_lines(&mut self, end_pos: BytePos) { } } + pub fn with_context(&mut self, f: F) -> Option + where + F: Fn(&RewriteContext) -> Option, + { + let context = self.get_context(); + let result = f(&context); + self.macro_rewrite_failure |= *context.macro_rewrite_failure.borrow(); + result + } + pub fn get_context(&self) -> RewriteContext { RewriteContext { parse_session: self.parse_session, - codemap: self.codemap, + source_map: self.source_map, config: self.config, - inside_macro: false, + inside_macro: RefCell::new(false), use_block: RefCell::new(false), - is_if_else_block: false, + is_if_else_block: RefCell::new(false), force_one_line_chain: RefCell::new(false), snippet_provider: self.snippet_provider, + macro_rewrite_failure: RefCell::new(false), + report: self.report.clone(), } } }