// 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;
pub struct FmtVisitor<'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
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<'b, 'a: 'b> FmtVisitor<'a> {
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)) {
) {
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.
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);
}
}
}
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);
}
}
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,
&FnSig::from_fn_kind(&fk, generics, fd, defaultness),
mk_sp(s.lo(), b.span.lo()),
b,
+ inner_attrs,
)
}
visit::FnKind::Closure(_) => unreachable!(),
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) {
let snippet = self.snippet(item.span);
let where_span_end = snippet
.find_uncommented("{")
- .map(|x| (BytePos(x as u32)) + source!(self, item.span).lo());
+ .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);
self.push_rewrite(item.span, rw);
}
let rw = format_trait(&self.get_context(), item, self.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);
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) => {
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);
}
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),
+ Some(generic_bounds),
&self.get_context(),
self.block_indent,
);
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)),
ii.ident,
ii.defaultness,
Some(ty),
- None,
&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,
+ 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);
}
// 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);
}
}
pub fn from_context(ctx: &'a RewriteContext) -> FmtVisitor<'a> {
- FmtVisitor::from_codemap(ctx.parse_session, ctx.config, ctx.snippet_provider)
+ FmtVisitor::from_source_map(
+ ctx.parse_session,
+ ctx.config,
+ ctx.snippet_provider,
+ ctx.report.clone(),
+ )
}
- 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 {
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(),
snippet_provider,
line_number: 0,
skipped_range: vec![],
+ macro_rewrite_failure: false,
+ report,
}
}
// 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" {
+ if 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;
}
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() {
}
}
- 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)) {
}
}
+ pub fn with_context<F>(&mut self, f: F) -> Option<String>
+ where
+ F: Fn(&RewriteContext) -> Option<String>,
+ {
+ let result;
+ let macro_rewrite_failure = {
+ let context = self.get_context();
+ result = f(&context);
+ unsafe { *context.macro_rewrite_failure.as_ptr() }
+ };
+ self.macro_rewrite_failure |= macro_rewrite_failure;
+ 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(),
}
}
}