Get rid of macro

This commit is contained in:
Seiichi Uchida 2018-02-18 02:54:54 +09:00
parent a915916f24
commit 333e3e1247
2 changed files with 64 additions and 53 deletions

View File

@ -14,7 +14,7 @@
//! order. Trait items are reordered in pre-determined order (associated types
//! and constatns comes before methods).
use config::lists::*;
use config::{Config, lists::*};
use syntax::{ast, attr, codemap::Span};
use codemap::LineRangeUtils;
@ -26,8 +26,7 @@
use shape::Shape;
use spanned::Spanned;
use utils::mk_sp;
use visitor::{filter_inline_attrs, is_extern_crate, is_mod_decl, is_use_item,
rewrite_extern_crate, FmtVisitor};
use visitor::{filter_inline_attrs, rewrite_extern_crate, FmtVisitor};
use std::cmp::Ordering;
@ -212,43 +211,70 @@ fn rewrite_reorderable_items(
write_list(&item_vec, &fmt)
}
fn contains_macro_use_attr(attrs: &[ast::Attribute], span: Span) -> bool {
attr::contains_name(&filter_inline_attrs(attrs, span), "macro_use")
fn contains_macro_use_attr(item: &ast::Item) -> bool {
attr::contains_name(&filter_inline_attrs(&item.attrs, item.span()), "macro_use")
}
/// Returns true for `mod foo;` without any inline attributes.
/// We cannot reorder modules with attributes because doing so can break the code.
/// e.g. `#[macro_use]`.
fn is_mod_decl_without_attr(item: &ast::Item) -> bool {
is_mod_decl(item) && !contains_macro_use_attr(&item.attrs, item.span())
/// A simplified version of `ast::ItemKind`.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
enum ReorderableItemKind {
ExternCrate,
Mod,
Use,
/// An item that cannot be reordered. Either has an unreorderable item kind
/// or an `macro_use` attribute.
Other,
}
fn is_use_item_without_attr(item: &ast::Item) -> bool {
is_use_item(item) && !contains_macro_use_attr(&item.attrs, item.span())
}
impl ReorderableItemKind {
pub fn from(item: &ast::Item) -> Self {
match item.node {
_ if contains_macro_use_attr(item) => ReorderableItemKind::Other,
ast::ItemKind::ExternCrate(..) => ReorderableItemKind::ExternCrate,
ast::ItemKind::Mod(..) => ReorderableItemKind::Mod,
ast::ItemKind::Use(..) => ReorderableItemKind::Use,
_ => ReorderableItemKind::Other,
}
}
fn is_extern_crate_without_attr(item: &ast::Item) -> bool {
is_extern_crate(item) && !contains_macro_use_attr(&item.attrs, item.span())
pub fn is_same_item_kind(&self, item: &ast::Item) -> bool {
ReorderableItemKind::from(item) == *self
}
pub fn is_reorderable(&self, config: &Config) -> bool {
match *self {
ReorderableItemKind::ExternCrate => config.reorder_extern_crates(),
ReorderableItemKind::Mod => config.reorder_modules(),
ReorderableItemKind::Use => config.reorder_imports(),
ReorderableItemKind::Other => false,
}
}
pub fn in_group(&self, config: &Config) -> bool {
match *self {
ReorderableItemKind::ExternCrate => config.reorder_extern_crates_in_group(),
ReorderableItemKind::Mod => config.reorder_modules(),
ReorderableItemKind::Use => config.reorder_imports_in_group(),
ReorderableItemKind::Other => false,
}
}
}
impl<'b, 'a: 'b> FmtVisitor<'a> {
/// Format items with the same item kind and reorder them. If `in_group` is
/// `true`, then the items separated by an empty line will not be reordered
/// together.
fn walk_items_with_reordering<F>(
fn walk_reorderable_items(
&mut self,
items: &[&ast::Item],
is_item: &F,
item_kind: ReorderableItemKind,
in_group: bool,
) -> usize
where
F: Fn(&ast::Item) -> bool,
{
) -> usize {
let mut last = self.codemap.lookup_line_range(items[0].span());
let item_length = items
.iter()
.take_while(|ppi| {
is_item(&***ppi) && (!in_group || {
item_kind.is_same_item_kind(&***ppi) && (!in_group || {
let current = self.codemap.lookup_line_range(ppi.span());
let in_same_group = current.lo < last.hi + 2;
last = current;
@ -280,38 +306,23 @@ fn walk_items_with_reordering<F>(
/// Visit and format the given items. Items are reordered If they are
/// consecutive and reorderable.
pub fn visit_items_with_reordering(&mut self, mut items: &[&ast::Item]) {
macro try_reorder_items_with($reorder: ident, $in_group: ident, $pred: ident) {
if self.config.$reorder() && $pred(&*items[0]) {
let used_items_len =
self.walk_items_with_reordering(items, &$pred, self.config.$in_group());
let (_, rest) = items.split_at(used_items_len);
items = rest;
continue;
}
}
while !items.is_empty() {
// If the next item is a `use`, `extern crate` or `mod`, then extract it and any
// subsequent items that have the same item kind to be reordered within
// `walk_items_with_reordering`. Otherwise, just format the next item for output.
{
try_reorder_items_with!(
reorder_imports,
reorder_imports_in_group,
is_use_item_without_attr
);
try_reorder_items_with!(
reorder_extern_crates,
reorder_extern_crates_in_group,
is_extern_crate_without_attr
);
try_reorder_items_with!(reorder_modules, reorder_modules, is_mod_decl_without_attr);
// `walk_reorderable_items`. Otherwise, just format the next item for output.
let item_kind = ReorderableItemKind::from(items[0]);
if item_kind.is_reorderable(self.config) {
let visited_items_num =
self.walk_reorderable_items(items, item_kind, item_kind.in_group(self.config));
let (_, rest) = items.split_at(visited_items_num);
items = rest;
} else {
// Reaching here means items were not reordered. There must be at least
// one item left in `items`, so calling `unwrap()` here is safe.
let (item, rest) = items.split_first().unwrap();
self.visit_item(item);
items = rest;
}
// Reaching here means items were not reordered. There must be at least
// one item left in `items`, so calling `unwrap()` here is safe.
let (item, rest) = items.split_first().unwrap();
self.visit_item(item);
items = rest;
}
}
}

View File

@ -42,21 +42,21 @@ pub fn filter_inline_attrs(attrs: &[ast::Attribute], outer_span: Span) -> Vec<as
}
/// Returns true for `mod foo;`, false for `mod foo { .. }`.
pub fn is_mod_decl(item: &ast::Item) -> bool {
fn is_mod_decl(item: &ast::Item) -> bool {
match item.node {
ast::ItemKind::Mod(ref m) => m.inner.hi() != item.span.hi(),
_ => false,
}
}
pub fn is_use_item(item: &ast::Item) -> bool {
fn is_use_item(item: &ast::Item) -> bool {
match item.node {
ast::ItemKind::Use(_) => true,
_ => false,
}
}
pub fn is_extern_crate(item: &ast::Item) -> bool {
fn is_extern_crate(item: &ast::Item) -> bool {
match item.node {
ast::ItemKind::ExternCrate(..) => true,
_ => false,