]> git.lizzy.rs Git - rust.git/blobdiff - src/visitor.rs
Use concat() instead of join("")
[rust.git] / src / visitor.rs
index 71a279d93aad0bdfba66f03bb1b3869321921e14..63e2c6bdcac57c88c8128682b20880aaa8975a67 100644 (file)
@@ -9,24 +9,29 @@
 // except according to those terms.
 
 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,
+    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;
 
@@ -55,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
@@ -66,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)
     }
@@ -76,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)
                 }
             }
@@ -112,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.
@@ -123,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);
             }
         }
 
@@ -190,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);
             }
         }
 
@@ -262,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,
@@ -345,20 +367,23 @@ pub fn visit_item(&mut self, item: &ast::Item) {
                 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);
+                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);
@@ -390,10 +415,10 @@ 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,
@@ -409,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);
             }
@@ -459,11 +494,12 @@ pub fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
                     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,
                 );
@@ -501,8 +537,18 @@ 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);
@@ -518,7 +564,7 @@ fn visit_mac(&mut self, mac: &ast::Mac, ident: Option<ast::Ident>, 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);
     }
 
@@ -552,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(),
@@ -571,6 +626,8 @@ pub fn from_codemap(
             snippet_provider,
             line_number: 0,
             skipped_range: vec![],
+            macro_rewrite_failure: false,
+            report,
         }
     }
 
@@ -584,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;
         }
@@ -645,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() {
@@ -680,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)) {
@@ -700,16 +787,28 @@ pub fn skip_empty_lines(&mut self, end_pos: BytePos) {
         }
     }
 
+    pub fn with_context<F>(&mut self, f: F) -> Option<String>
+    where
+        F: Fn(&RewriteContext) -> Option<String>,
+    {
+        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: RefCell::new(false),
             use_block: RefCell::new(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(),
         }
     }
 }