]> git.lizzy.rs Git - rust.git/commitdiff
Add attr module
authortopecongiro <seuchida@gmail.com>
Fri, 23 Feb 2018 13:30:05 +0000 (22:30 +0900)
committertopecongiro <seuchida@gmail.com>
Fri, 23 Feb 2018 13:30:05 +0000 (22:30 +0900)
rustfmt-core/src/attr.rs [new file with mode: 0644]
rustfmt-core/src/lib.rs
rustfmt-core/src/visitor.rs

diff --git a/rustfmt-core/src/attr.rs b/rustfmt-core/src/attr.rs
new file mode 100644 (file)
index 0000000..75d98a7
--- /dev/null
@@ -0,0 +1,304 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Format attributes and meta items.
+
+use config::lists::*;
+use syntax::ast;
+
+use comment::{combine_strs_with_missing_comments, contains_comment, rewrite_doc_comment};
+use expr::rewrite_literal;
+use lists::{itemize_list, write_list, ListFormatting};
+use rewrite::{Rewrite, RewriteContext};
+use shape::Shape;
+use utils::{count_newlines, mk_sp};
+
+use std::cmp;
+
+/// Returns attributes on the given statement.
+pub fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] {
+    match stmt.node {
+        ast::StmtKind::Local(ref local) => &local.attrs,
+        ast::StmtKind::Item(ref item) => &item.attrs,
+        ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => &expr.attrs,
+        ast::StmtKind::Mac(ref mac) => &mac.2,
+    }
+}
+
+fn is_derive(attr: &ast::Attribute) -> bool {
+    attr.check_name("derive")
+}
+
+/// Returns the arguments of `#[derive(...)]`.
+fn get_derive_args<'a>(context: &'a RewriteContext, attr: &ast::Attribute) -> Option<Vec<&'a str>> {
+    attr.meta_item_list().map(|meta_item_list| {
+        meta_item_list
+            .iter()
+            .map(|nested_meta_item| context.snippet(nested_meta_item.span))
+            .collect()
+    })
+}
+
+// Format `#[derive(..)]`, using visual indent & mixed style when we need to go multiline.
+fn format_derive(context: &RewriteContext, derive_args: &[&str], shape: Shape) -> Option<String> {
+    let mut result = String::with_capacity(128);
+    result.push_str("#[derive(");
+    // 11 = `#[derive()]`
+    let initial_budget = shape.width.checked_sub(11)?;
+    let mut budget = initial_budget;
+    let num = derive_args.len();
+    for (i, a) in derive_args.iter().enumerate() {
+        // 2 = `, ` or `)]`
+        let width = a.len() + 2;
+        if width > budget {
+            if i > 0 {
+                // Remove trailing whitespace.
+                result.pop();
+            }
+            result.push('\n');
+            // 9 = `#[derive(`
+            result.push_str(&(shape.indent + 9).to_string(context.config));
+            budget = initial_budget;
+        } else {
+            budget = budget.checked_sub(width).unwrap_or(0);
+        }
+        result.push_str(a);
+        if i != num - 1 {
+            result.push_str(", ")
+        }
+    }
+    result.push_str(")]");
+    Some(result)
+}
+
+/// Returns the first group of attributes that fills the given predicate.
+/// We consider two doc comments are in different group if they are separated by normal comments.
+fn take_while_with_pred<'a, P>(
+    context: &RewriteContext,
+    attrs: &'a [ast::Attribute],
+    pred: P,
+) -> &'a [ast::Attribute]
+where
+    P: Fn(&ast::Attribute) -> bool,
+{
+    let mut last_index = 0;
+    let mut iter = attrs.iter().enumerate().peekable();
+    while let Some((i, attr)) = iter.next() {
+        if !pred(attr) {
+            break;
+        }
+        if let Some(&(_, next_attr)) = iter.peek() {
+            // Extract comments between two attributes.
+            let span_between_attr = mk_sp(attr.span.hi(), next_attr.span.lo());
+            let snippet = context.snippet(span_between_attr);
+            if count_newlines(snippet) >= 2 || snippet.contains('/') {
+                break;
+            }
+        }
+        last_index = i;
+    }
+    if last_index == 0 {
+        &[]
+    } else {
+        &attrs[..last_index + 1]
+    }
+}
+
+fn rewrite_first_group_attrs(
+    context: &RewriteContext,
+    attrs: &[ast::Attribute],
+    shape: Shape,
+) -> Option<(usize, String)> {
+    if attrs.is_empty() {
+        return Some((0, String::new()));
+    }
+    // Rewrite doc comments
+    let sugared_docs = take_while_with_pred(context, attrs, |a| a.is_sugared_doc);
+    if !sugared_docs.is_empty() {
+        let snippet = sugared_docs
+            .iter()
+            .map(|a| context.snippet(a.span))
+            .collect::<Vec<_>>()
+            .join("\n");
+        return Some((
+            sugared_docs.len(),
+            rewrite_doc_comment(&snippet, shape, context.config)?,
+        ));
+    }
+    // Rewrite `#[derive(..)]`s.
+    if context.config.merge_derives() {
+        let derives = take_while_with_pred(context, attrs, is_derive);
+        if !derives.is_empty() {
+            let mut derive_args = vec![];
+            for derive in derives {
+                derive_args.append(&mut get_derive_args(context, derive)?);
+            }
+            return Some((derives.len(), format_derive(context, &derive_args, shape)?));
+        }
+    }
+    // Rewrite the first attribute.
+    Some((1, attrs[0].rewrite(context, shape)?))
+}
+
+impl Rewrite for ast::NestedMetaItem {
+    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+        match self.node {
+            ast::NestedMetaItemKind::MetaItem(ref meta_item) => meta_item.rewrite(context, shape),
+            ast::NestedMetaItemKind::Literal(ref l) => rewrite_literal(context, l, shape),
+        }
+    }
+}
+
+fn has_newlines_before_after_comment(comment: &str) -> (&str, &str) {
+    // Look at before and after comment and see if there are any empty lines.
+    let comment_begin = comment.chars().position(|c| c == '/');
+    let len = comment_begin.unwrap_or_else(|| comment.len());
+    let mlb = count_newlines(&comment[..len]) > 1;
+    let mla = if comment_begin.is_none() {
+        mlb
+    } else {
+        let comment_end = comment.chars().rev().position(|c| !c.is_whitespace());
+        let len = comment_end.unwrap();
+        comment
+            .chars()
+            .rev()
+            .take(len)
+            .filter(|c| *c == '\n')
+            .count() > 1
+    };
+    (if mlb { "\n" } else { "" }, if mla { "\n" } else { "" })
+}
+
+impl Rewrite for ast::MetaItem {
+    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+        Some(match self.node {
+            ast::MetaItemKind::Word => String::from(&*self.name.as_str()),
+            ast::MetaItemKind::List(ref list) => {
+                let name = self.name.as_str();
+                // 1 = `(`, 2 = `]` and `)`
+                let item_shape = shape
+                    .visual_indent(0)
+                    .shrink_left(name.len() + 1)
+                    .and_then(|s| s.sub_width(2))?;
+                let items = itemize_list(
+                    context.snippet_provider,
+                    list.iter(),
+                    ")",
+                    ",",
+                    |nested_meta_item| nested_meta_item.span.lo(),
+                    |nested_meta_item| nested_meta_item.span.hi(),
+                    |nested_meta_item| nested_meta_item.rewrite(context, item_shape),
+                    self.span.lo(),
+                    self.span.hi(),
+                    false,
+                );
+                let item_vec = items.collect::<Vec<_>>();
+                let fmt = ListFormatting {
+                    tactic: DefinitiveListTactic::Mixed,
+                    separator: ",",
+                    trailing_separator: SeparatorTactic::Never,
+                    separator_place: SeparatorPlace::Back,
+                    shape: item_shape,
+                    ends_with_newline: false,
+                    preserve_newline: false,
+                    config: context.config,
+                };
+                format!("{}({})", name, write_list(&item_vec, &fmt)?)
+            }
+            ast::MetaItemKind::NameValue(ref literal) => {
+                let name = self.name.as_str();
+                // 3 = ` = `
+                let lit_shape = shape.shrink_left(name.len() + 3)?;
+                let value = rewrite_literal(context, literal, lit_shape)?;
+                format!("{} = {}", name, value)
+            }
+        })
+    }
+}
+
+impl Rewrite for ast::Attribute {
+    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+        let prefix = match self.style {
+            ast::AttrStyle::Inner => "#!",
+            ast::AttrStyle::Outer => "#",
+        };
+        let snippet = context.snippet(self.span);
+        if self.is_sugared_doc {
+            let doc_shape = Shape {
+                width: cmp::min(shape.width, context.config.comment_width())
+                    .checked_sub(shape.indent.width())
+                    .unwrap_or(0),
+                ..shape
+            };
+            rewrite_doc_comment(snippet, doc_shape, context.config)
+        } else {
+            if contains_comment(snippet) {
+                return Some(snippet.to_owned());
+            }
+            // 1 = `[`
+            let shape = shape.offset_left(prefix.len() + 1)?;
+            Some(
+                self.meta()
+                    .and_then(|meta| meta.rewrite(context, shape))
+                    .map_or_else(|| snippet.to_owned(), |rw| format!("{}[{}]", prefix, rw)),
+            )
+        }
+    }
+}
+
+impl<'a> Rewrite for [ast::Attribute] {
+    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+        if self.is_empty() {
+            return Some(String::new());
+        }
+        let (first_group_len, first_group_str) = rewrite_first_group_attrs(context, self, shape)?;
+        if self.len() == 1 || first_group_len == self.len() {
+            Some(first_group_str)
+        } else {
+            let rest_str = self[first_group_len..].rewrite(context, shape)?;
+            let missing_span = mk_sp(
+                self[first_group_len - 1].span.hi(),
+                self[first_group_len].span.lo(),
+            );
+            // Preserve an empty line before/after doc comments.
+            if self[0].is_sugared_doc || self[first_group_len].is_sugared_doc {
+                let snippet = context.snippet(missing_span);
+                let (mla, mlb) = has_newlines_before_after_comment(snippet);
+                let comment = ::comment::recover_missing_comment_in_span(
+                    missing_span,
+                    shape.with_max_width(context.config),
+                    context,
+                    0,
+                )?;
+                let comment = if comment.is_empty() {
+                    format!("\n{}", mlb)
+                } else {
+                    format!("{}{}\n{}", mla, comment, mlb)
+                };
+                Some(format!(
+                    "{}{}{}{}",
+                    first_group_str,
+                    comment,
+                    shape.indent.to_string(context.config),
+                    rest_str
+                ))
+            } else {
+                combine_strs_with_missing_comments(
+                    context,
+                    &first_group_str,
+                    &rest_str,
+                    missing_span,
+                    shape,
+                    false,
+                )
+            }
+        }
+    }
+}
index 5697d6cab2d36a8bcd93c1c6660b47b49e3f1c62..6e9554f68554a008a4263b4a8916f72122348027 100644 (file)
@@ -53,6 +53,7 @@
 #[macro_use]
 mod utils;
 
+mod attr;
 mod chains;
 mod checkstyle;
 mod closures;
index b3d3e3270e834be826ba1193f7aa219b0ead0a83..8a6fb3f169c65ed58040a3fd6098ce113cee6a95 100644 (file)
@@ -8,23 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::cmp;
-
-use config::lists::*;
 use syntax::{ast, visit};
 use syntax::attr::HasAttrs;
 use syntax::codemap::{self, BytePos, CodeMap, Pos, Span};
 use syntax::parse::ParseSess;
 
+use attr::*;
 use codemap::{LineRangeUtils, SpanUtils};
-use comment::{combine_strs_with_missing_comments, contains_comment, CodeCharKind,
-              CommentCodeSlices, FindUncommented};
-use comment::rewrite_doc_comment;
+use comment::{contains_comment, CodeCharKind, CommentCodeSlices, FindUncommented};
 use config::{BraceStyle, Config};
-use expr::rewrite_literal;
 use items::{format_impl, format_trait, format_trait_alias, rewrite_associated_impl_type,
             rewrite_associated_type, rewrite_type_alias, FnSig, StaticParts, StructParts};
-use lists::{itemize_list, write_list, ListFormatting};
 use macros::{rewrite_macro, rewrite_macro_def, MacroPosition};
 use regex::Regex;
 use rewrite::{Rewrite, RewriteContext};
@@ -736,277 +730,6 @@ pub fn get_context(&self) -> RewriteContext {
     }
 }
 
-impl Rewrite for ast::NestedMetaItem {
-    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
-        match self.node {
-            ast::NestedMetaItemKind::MetaItem(ref meta_item) => meta_item.rewrite(context, shape),
-            ast::NestedMetaItemKind::Literal(ref l) => rewrite_literal(context, l, shape),
-        }
-    }
-}
-
-impl Rewrite for ast::MetaItem {
-    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
-        Some(match self.node {
-            ast::MetaItemKind::Word => String::from(&*self.name.as_str()),
-            ast::MetaItemKind::List(ref list) => {
-                let name = self.name.as_str();
-                // 1 = `(`, 2 = `]` and `)`
-                let item_shape = shape
-                    .visual_indent(0)
-                    .shrink_left(name.len() + 1)
-                    .and_then(|s| s.sub_width(2))?;
-                let items = itemize_list(
-                    context.snippet_provider,
-                    list.iter(),
-                    ")",
-                    ",",
-                    |nested_meta_item| nested_meta_item.span.lo(),
-                    |nested_meta_item| nested_meta_item.span.hi(),
-                    |nested_meta_item| nested_meta_item.rewrite(context, item_shape),
-                    self.span.lo(),
-                    self.span.hi(),
-                    false,
-                );
-                let item_vec = items.collect::<Vec<_>>();
-                let fmt = ListFormatting {
-                    tactic: DefinitiveListTactic::Mixed,
-                    separator: ",",
-                    trailing_separator: SeparatorTactic::Never,
-                    separator_place: SeparatorPlace::Back,
-                    shape: item_shape,
-                    ends_with_newline: false,
-                    preserve_newline: false,
-                    config: context.config,
-                };
-                format!("{}({})", name, write_list(&item_vec, &fmt)?)
-            }
-            ast::MetaItemKind::NameValue(ref literal) => {
-                let name = self.name.as_str();
-                // 3 = ` = `
-                let lit_shape = shape.shrink_left(name.len() + 3)?;
-                let value = rewrite_literal(context, literal, lit_shape)?;
-                format!("{} = {}", name, value)
-            }
-        })
-    }
-}
-
-impl Rewrite for ast::Attribute {
-    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
-        let prefix = match self.style {
-            ast::AttrStyle::Inner => "#!",
-            ast::AttrStyle::Outer => "#",
-        };
-        let snippet = context.snippet(self.span);
-        if self.is_sugared_doc {
-            let doc_shape = Shape {
-                width: cmp::min(shape.width, context.config.comment_width())
-                    .checked_sub(shape.indent.width())
-                    .unwrap_or(0),
-                ..shape
-            };
-            rewrite_doc_comment(snippet, doc_shape, context.config)
-        } else {
-            if contains_comment(snippet) {
-                return Some(snippet.to_owned());
-            }
-            // 1 = `[`
-            let shape = shape.offset_left(prefix.len() + 1)?;
-            Some(
-                self.meta()
-                    .and_then(|meta| meta.rewrite(context, shape))
-                    .map_or_else(|| snippet.to_owned(), |rw| format!("{}[{}]", prefix, rw)),
-            )
-        }
-    }
-}
-
-/// Returns the first group of attributes that fills the given predicate.
-/// We consider two doc comments are in different group if they are separated by normal comments.
-fn take_while_with_pred<'a, P>(
-    context: &RewriteContext,
-    attrs: &'a [ast::Attribute],
-    pred: P,
-) -> &'a [ast::Attribute]
-where
-    P: Fn(&ast::Attribute) -> bool,
-{
-    let mut last_index = 0;
-    let mut iter = attrs.iter().enumerate().peekable();
-    while let Some((i, attr)) = iter.next() {
-        if !pred(attr) {
-            break;
-        }
-        if let Some(&(_, next_attr)) = iter.peek() {
-            // Extract comments between two attributes.
-            let span_between_attr = mk_sp(attr.span.hi(), next_attr.span.lo());
-            let snippet = context.snippet(span_between_attr);
-            if count_newlines(snippet) >= 2 || snippet.contains('/') {
-                break;
-            }
-        }
-        last_index = i;
-    }
-    if last_index == 0 {
-        &[]
-    } else {
-        &attrs[..last_index + 1]
-    }
-}
-
-fn rewrite_first_group_attrs(
-    context: &RewriteContext,
-    attrs: &[ast::Attribute],
-    shape: Shape,
-) -> Option<(usize, String)> {
-    if attrs.is_empty() {
-        return Some((0, String::new()));
-    }
-    // Rewrite doc comments
-    let sugared_docs = take_while_with_pred(context, attrs, |a| a.is_sugared_doc);
-    if !sugared_docs.is_empty() {
-        let snippet = sugared_docs
-            .iter()
-            .map(|a| context.snippet(a.span))
-            .collect::<Vec<_>>()
-            .join("\n");
-        return Some((
-            sugared_docs.len(),
-            rewrite_doc_comment(&snippet, shape, context.config)?,
-        ));
-    }
-    // Rewrite `#[derive(..)]`s.
-    if context.config.merge_derives() {
-        let derives = take_while_with_pred(context, attrs, is_derive);
-        if !derives.is_empty() {
-            let mut derive_args = vec![];
-            for derive in derives {
-                derive_args.append(&mut get_derive_args(context, derive)?);
-            }
-            return Some((derives.len(), format_derive(context, &derive_args, shape)?));
-        }
-    }
-    // Rewrite the first attribute.
-    Some((1, attrs[0].rewrite(context, shape)?))
-}
-
-fn has_newlines_before_after_comment(comment: &str) -> (&str, &str) {
-    // Look at before and after comment and see if there are any empty lines.
-    let comment_begin = comment.chars().position(|c| c == '/');
-    let len = comment_begin.unwrap_or_else(|| comment.len());
-    let mlb = count_newlines(&comment[..len]) > 1;
-    let mla = if comment_begin.is_none() {
-        mlb
-    } else {
-        let comment_end = comment.chars().rev().position(|c| !c.is_whitespace());
-        let len = comment_end.unwrap();
-        comment
-            .chars()
-            .rev()
-            .take(len)
-            .filter(|c| *c == '\n')
-            .count() > 1
-    };
-    (if mlb { "\n" } else { "" }, if mla { "\n" } else { "" })
-}
-
-impl<'a> Rewrite for [ast::Attribute] {
-    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
-        if self.is_empty() {
-            return Some(String::new());
-        }
-        let (first_group_len, first_group_str) = rewrite_first_group_attrs(context, self, shape)?;
-        if self.len() == 1 || first_group_len == self.len() {
-            Some(first_group_str)
-        } else {
-            let rest_str = self[first_group_len..].rewrite(context, shape)?;
-            let missing_span = mk_sp(
-                self[first_group_len - 1].span.hi(),
-                self[first_group_len].span.lo(),
-            );
-            // Preserve an empty line before/after doc comments.
-            if self[0].is_sugared_doc || self[first_group_len].is_sugared_doc {
-                let snippet = context.snippet(missing_span);
-                let (mla, mlb) = has_newlines_before_after_comment(snippet);
-                let comment = ::comment::recover_missing_comment_in_span(
-                    missing_span,
-                    shape.with_max_width(context.config),
-                    context,
-                    0,
-                )?;
-                let comment = if comment.is_empty() {
-                    format!("\n{}", mlb)
-                } else {
-                    format!("{}{}\n{}", mla, comment, mlb)
-                };
-                Some(format!(
-                    "{}{}{}{}",
-                    first_group_str,
-                    comment,
-                    shape.indent.to_string(context.config),
-                    rest_str
-                ))
-            } else {
-                combine_strs_with_missing_comments(
-                    context,
-                    &first_group_str,
-                    &rest_str,
-                    missing_span,
-                    shape,
-                    false,
-                )
-            }
-        }
-    }
-}
-
-// Format `#[derive(..)]`, using visual indent & mixed style when we need to go multiline.
-fn format_derive(context: &RewriteContext, derive_args: &[&str], shape: Shape) -> Option<String> {
-    let mut result = String::with_capacity(128);
-    result.push_str("#[derive(");
-    // 11 = `#[derive()]`
-    let initial_budget = shape.width.checked_sub(11)?;
-    let mut budget = initial_budget;
-    let num = derive_args.len();
-    for (i, a) in derive_args.iter().enumerate() {
-        // 2 = `, ` or `)]`
-        let width = a.len() + 2;
-        if width > budget {
-            if i > 0 {
-                // Remove trailing whitespace.
-                result.pop();
-            }
-            result.push('\n');
-            // 9 = `#[derive(`
-            result.push_str(&(shape.indent + 9).to_string(context.config));
-            budget = initial_budget;
-        } else {
-            budget = budget.checked_sub(width).unwrap_or(0);
-        }
-        result.push_str(a);
-        if i != num - 1 {
-            result.push_str(", ")
-        }
-    }
-    result.push_str(")]");
-    Some(result)
-}
-
-fn is_derive(attr: &ast::Attribute) -> bool {
-    attr.check_name("derive")
-}
-
-/// Returns the arguments of `#[derive(...)]`.
-fn get_derive_args<'a>(context: &'a RewriteContext, attr: &ast::Attribute) -> Option<Vec<&'a str>> {
-    attr.meta_item_list().map(|meta_item_list| {
-        meta_item_list
-            .iter()
-            .map(|nested_meta_item| context.snippet(nested_meta_item.span))
-            .collect()
-    })
-}
-
 // Rewrite `extern crate foo;` WITHOUT attributes.
 pub fn rewrite_extern_crate(context: &RewriteContext, item: &ast::Item) -> Option<String> {
     assert!(is_extern_crate(item));
@@ -1018,12 +741,3 @@ pub fn rewrite_extern_crate(context: &RewriteContext, item: &ast::Item) -> Optio
         String::from(&*Regex::new(r"\s;").unwrap().replace(no_whitespace, ";"))
     })
 }
-
-fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] {
-    match stmt.node {
-        ast::StmtKind::Local(ref local) => &local.attrs,
-        ast::StmtKind::Item(ref item) => &item.attrs,
-        ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => &expr.attrs,
-        ast::StmtKind::Mac(ref mac) => &mac.2,
-    }
-}