mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-12 08:36:03 +00:00
Merge pull request #122 from cassiersg/fix-mod
Reformat modules in external files
This commit is contained in:
commit
04cf309f32
@ -35,11 +35,9 @@ pub struct ChangeSet<'a> {
|
||||
impl<'a> ChangeSet<'a> {
|
||||
// Create a new ChangeSet for a given libsyntax CodeMap.
|
||||
pub fn from_codemap(codemap: &'a CodeMap) -> ChangeSet<'a> {
|
||||
let mut result = ChangeSet {
|
||||
file_map: HashMap::new(),
|
||||
codemap: codemap,
|
||||
file_spans: Vec::with_capacity(codemap.files.borrow().len()),
|
||||
};
|
||||
let mut result = ChangeSet { file_map: HashMap::new(),
|
||||
codemap: codemap,
|
||||
file_spans: Vec::with_capacity(codemap.files.borrow().len()), };
|
||||
|
||||
for f in codemap.files.borrow().iter() {
|
||||
// Use the length of the file as a heuristic for how much space we
|
||||
@ -116,11 +114,7 @@ impl<'a> ChangeSet<'a> {
|
||||
|
||||
// Return an iterator over the entire changed text.
|
||||
pub fn text<'c>(&'c self) -> FileIterator<'c, 'a> {
|
||||
FileIterator {
|
||||
change_set: self,
|
||||
keys: self.file_map.keys().collect(),
|
||||
cur_key: 0,
|
||||
}
|
||||
FileIterator { change_set: self, keys: self.file_map.keys().collect(), cur_key: 0 }
|
||||
}
|
||||
|
||||
// Append a newline to the end of each file.
|
||||
@ -153,12 +147,11 @@ impl<'a> ChangeSet<'a> {
|
||||
let text = &self.file_map[filename];
|
||||
|
||||
// prints all newlines either as `\n` or as `\r\n`
|
||||
fn write_system_newlines<T>(
|
||||
mut writer: T,
|
||||
text: &StringBuffer,
|
||||
config: &Config)
|
||||
-> Result<(), ::std::io::Error>
|
||||
where T: Write,
|
||||
fn write_system_newlines<T>(mut writer: T,
|
||||
text: &StringBuffer,
|
||||
config: &Config)
|
||||
-> Result<(), ::std::io::Error>
|
||||
where T: Write
|
||||
{
|
||||
match config.newline_style {
|
||||
NewlineStyle::Unix => write!(writer, "{}", text),
|
||||
@ -213,6 +206,10 @@ impl<'a> ChangeSet<'a> {
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn is_changed(&self, filename: &str) -> bool {
|
||||
self.file_map.get(filename).expect("Unknown filename").len != 0
|
||||
}
|
||||
}
|
||||
|
||||
// Iterates over each file in the ChangSet. Yields the filename and the changed
|
||||
|
@ -24,15 +24,13 @@ pub fn rewrite_comment(orig: &str, block_style: bool, width: usize, offset: usiz
|
||||
let max_chars = width.checked_sub(closer.len()).unwrap_or(1)
|
||||
.checked_sub(opener.len()).unwrap_or(1);
|
||||
|
||||
let fmt = StringFormat {
|
||||
opener: "",
|
||||
closer: "",
|
||||
line_start: line_start,
|
||||
line_end: "",
|
||||
width: max_chars,
|
||||
offset: offset + opener.len() - line_start.len(),
|
||||
trim_end: true
|
||||
};
|
||||
let fmt = StringFormat { opener: "",
|
||||
closer: "",
|
||||
line_start: line_start,
|
||||
line_end: "",
|
||||
width: max_chars,
|
||||
offset: offset + opener.len() - line_start.len(),
|
||||
trim_end: true, };
|
||||
|
||||
let indent_str = make_indent(offset);
|
||||
let line_breaks = s.chars().filter(|&c| c == '\n').count();
|
||||
@ -102,8 +100,8 @@ fn format_comments() {
|
||||
|
||||
let input = "// comment";
|
||||
let expected_output = "/* com\n \
|
||||
* men\n \
|
||||
* t */";
|
||||
* men\n \
|
||||
* t */";
|
||||
assert_eq!(expected_output, rewrite_comment(input, true, 9, 69));
|
||||
|
||||
assert_eq!("/* trimmed */", rewrite_comment("/* trimmed */", true, 100, 100));
|
||||
|
85
src/expr.rs
85
src/expr.rs
@ -63,7 +63,7 @@ fn rewrite_string_lit(context: &RewriteContext,
|
||||
span: Span,
|
||||
width: usize,
|
||||
offset: usize)
|
||||
-> Option<String> {
|
||||
-> Option<String> {
|
||||
// Check if there is anything to fix: we always try to fixup multi-line
|
||||
// strings, or if the string is too long for the line.
|
||||
let l_loc = context.codemap.lookup_char_pos(span.lo);
|
||||
@ -71,15 +71,13 @@ fn rewrite_string_lit(context: &RewriteContext,
|
||||
if l_loc.line == r_loc.line && r_loc.col.to_usize() <= context.config.max_width {
|
||||
return context.codemap.span_to_snippet(span).ok();
|
||||
}
|
||||
let fmt = StringFormat {
|
||||
opener: "\"",
|
||||
closer: "\"",
|
||||
line_start: " ",
|
||||
line_end: "\\",
|
||||
width: width,
|
||||
offset: offset,
|
||||
trim_end: false
|
||||
};
|
||||
let fmt = StringFormat { opener: "\"",
|
||||
closer: "\"",
|
||||
line_start: " ",
|
||||
line_end: "\\",
|
||||
width: width,
|
||||
offset: offset,
|
||||
trim_end: false, };
|
||||
|
||||
Some(rewrite_string(&s.escape_default(), &fmt))
|
||||
}
|
||||
@ -90,7 +88,7 @@ fn rewrite_call(context: &RewriteContext,
|
||||
span: Span,
|
||||
width: usize,
|
||||
offset: usize)
|
||||
-> Option<String> {
|
||||
-> Option<String> {
|
||||
debug!("rewrite_call, width: {}, offset: {}", width, offset);
|
||||
|
||||
// TODO using byte lens instead of char lens (and probably all over the place too)
|
||||
@ -119,20 +117,22 @@ fn rewrite_call(context: &RewriteContext,
|
||||
callee.span.hi + BytePos(1),
|
||||
span.hi);
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: ListTactic::HorizontalVertical,
|
||||
separator: ",",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
indent: offset,
|
||||
h_width: remaining_width,
|
||||
v_width: remaining_width,
|
||||
ends_with_newline: true,
|
||||
};
|
||||
let fmt = ListFormatting { tactic: ListTactic::HorizontalVertical,
|
||||
separator: ",",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
indent: offset,
|
||||
h_width: remaining_width,
|
||||
v_width: remaining_width,
|
||||
ends_with_newline: true, };
|
||||
|
||||
Some(format!("{}({})", callee_str, write_list(&items, &fmt)))
|
||||
}
|
||||
|
||||
fn rewrite_paren(context: &RewriteContext, subexpr: &ast::Expr, width: usize, offset: usize) -> Option<String> {
|
||||
fn rewrite_paren(context: &RewriteContext,
|
||||
subexpr: &ast::Expr,
|
||||
width: usize,
|
||||
offset: usize)
|
||||
-> Option<String> {
|
||||
debug!("rewrite_paren, width: {}, offset: {}", width, offset);
|
||||
// 1 is for opening paren, 2 is for opening+closing, we want to keep the closing
|
||||
// paren on the same line as the subexpr
|
||||
@ -148,14 +148,13 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
|
||||
span: Span,
|
||||
width: usize,
|
||||
offset: usize)
|
||||
-> Option<String>
|
||||
{
|
||||
-> Option<String> {
|
||||
debug!("rewrite_struct_lit: width {}, offset {}", width, offset);
|
||||
assert!(fields.len() > 0 || base.is_some());
|
||||
|
||||
enum StructLitField<'a> {
|
||||
Regular(&'a ast::Field),
|
||||
Base(&'a ast::Expr)
|
||||
Base(&'a ast::Expr),
|
||||
}
|
||||
|
||||
let path_str = pprust::path_to_string(path);
|
||||
@ -203,19 +202,17 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
|
||||
span_after(span, "{", context.codemap),
|
||||
span.hi);
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: ListTactic::HorizontalVertical,
|
||||
separator: ",",
|
||||
trailing_separator: if base.is_some() {
|
||||
let fmt = ListFormatting { tactic: ListTactic::HorizontalVertical,
|
||||
separator: ",",
|
||||
trailing_separator: if base.is_some() {
|
||||
SeparatorTactic::Never
|
||||
} else {
|
||||
context.config.struct_lit_trailing_comma
|
||||
},
|
||||
indent: indent,
|
||||
h_width: budget,
|
||||
v_width: budget,
|
||||
ends_with_newline: true,
|
||||
};
|
||||
indent: indent,
|
||||
h_width: budget,
|
||||
v_width: budget,
|
||||
ends_with_newline: true, };
|
||||
let fields_str = write_list(&items, &fmt);
|
||||
Some(format!("{} {{ {} }}", path_str, fields_str))
|
||||
|
||||
@ -225,7 +222,11 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
|
||||
// }
|
||||
}
|
||||
|
||||
fn rewrite_field(context: &RewriteContext, field: &ast::Field, width: usize, offset: usize) -> Option<String> {
|
||||
fn rewrite_field(context: &RewriteContext,
|
||||
field: &ast::Field,
|
||||
width: usize,
|
||||
offset: usize)
|
||||
-> Option<String> {
|
||||
let name = &token::get_ident(field.ident.node);
|
||||
let overhead = name.len() + 2;
|
||||
let expr = field.expr.rewrite(context, width - overhead, offset + overhead);
|
||||
@ -262,15 +263,13 @@ fn rewrite_tuple_lit(context: &RewriteContext,
|
||||
SeparatorTactic::Never
|
||||
};
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: ListTactic::HorizontalVertical,
|
||||
separator: ",",
|
||||
trailing_separator: trailing_separator_tactic,
|
||||
indent: indent,
|
||||
h_width: width - 2,
|
||||
v_width: width - 2,
|
||||
ends_with_newline: true,
|
||||
};
|
||||
let fmt = ListFormatting { tactic: ListTactic::HorizontalVertical,
|
||||
separator: ",",
|
||||
trailing_separator: trailing_separator_tactic,
|
||||
indent: indent,
|
||||
h_width: width - 2,
|
||||
v_width: width - 2,
|
||||
ends_with_newline: true, };
|
||||
|
||||
Some(format!("({})", write_list(&items, &fmt)))
|
||||
}
|
||||
|
@ -48,7 +48,8 @@ impl<'a> FmtVisitor<'a> {
|
||||
path: &ast::Path,
|
||||
path_list: &[ast::PathListItem],
|
||||
visibility: ast::Visibility,
|
||||
span: Span) -> Option<String> {
|
||||
span: Span)
|
||||
-> Option<String> {
|
||||
let path_str = pprust::path_to_string(path);
|
||||
let vis = format_visibility(visibility);
|
||||
|
||||
@ -70,18 +71,17 @@ impl<'a> FmtVisitor<'a> {
|
||||
let remaining_line_budget = one_line_budget.checked_sub(used_width).unwrap_or(0);
|
||||
let remaining_multi_budget = multi_line_budget.checked_sub(used_width).unwrap_or(0);
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: ListTactic::Mixed,
|
||||
separator: ",",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
indent: block_indent + indent,
|
||||
h_width: remaining_line_budget,
|
||||
v_width: remaining_multi_budget,
|
||||
ends_with_newline: true,
|
||||
};
|
||||
let fmt = ListFormatting { tactic: ListTactic::Mixed,
|
||||
separator: ",",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
indent: block_indent + indent,
|
||||
h_width: remaining_line_budget,
|
||||
v_width: remaining_multi_budget,
|
||||
ends_with_newline: true, };
|
||||
|
||||
let mut items = itemize_list(self.codemap,
|
||||
vec![ListItem::from_str("")], // Dummy value, explanation below
|
||||
vec![ListItem::from_str("")], /* Dummy value, explanation
|
||||
* below */
|
||||
path_list.iter(),
|
||||
",",
|
||||
"}",
|
||||
|
@ -21,7 +21,7 @@ static FIX_ME_CHARS: &'static [char] = &['F', 'I', 'X', 'M', 'E'];
|
||||
pub enum ReportTactic {
|
||||
Always,
|
||||
Unnumbered,
|
||||
Never
|
||||
Never,
|
||||
}
|
||||
|
||||
impl ReportTactic {
|
||||
@ -40,12 +40,12 @@ impl_enum_decodable!(ReportTactic, Always, Unnumbered, Never);
|
||||
enum Seeking {
|
||||
Issue {
|
||||
todo_idx: usize,
|
||||
fixme_idx: usize
|
||||
fixme_idx: usize,
|
||||
},
|
||||
Number {
|
||||
issue: Issue,
|
||||
part: NumberPart
|
||||
}
|
||||
part: NumberPart,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@ -53,7 +53,7 @@ enum NumberPart {
|
||||
OpenParen,
|
||||
Pound,
|
||||
Number,
|
||||
CloseParen
|
||||
CloseParen,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||
@ -79,13 +79,13 @@ impl fmt::Display for Issue {
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||
enum IssueType {
|
||||
Todo,
|
||||
Fixme
|
||||
Fixme,
|
||||
}
|
||||
|
||||
enum IssueClassification {
|
||||
Good,
|
||||
Bad(Issue),
|
||||
None
|
||||
None,
|
||||
}
|
||||
|
||||
pub struct BadIssueSeeker {
|
||||
@ -96,11 +96,9 @@ pub struct BadIssueSeeker {
|
||||
|
||||
impl BadIssueSeeker {
|
||||
pub fn new(report_todo: ReportTactic, report_fixme: ReportTactic) -> BadIssueSeeker {
|
||||
BadIssueSeeker {
|
||||
state: Seeking::Issue { todo_idx: 0, fixme_idx: 0 },
|
||||
report_todo: report_todo,
|
||||
report_fixme: report_fixme,
|
||||
}
|
||||
BadIssueSeeker { state: Seeking::Issue { todo_idx: 0, fixme_idx: 0 },
|
||||
report_todo: report_todo,
|
||||
report_fixme: report_fixme, }
|
||||
}
|
||||
|
||||
// Check whether or not the current char is conclusive evidence for an
|
||||
@ -176,8 +174,7 @@ impl BadIssueSeeker {
|
||||
c: char,
|
||||
issue: Issue,
|
||||
mut part: NumberPart)
|
||||
-> IssueClassification
|
||||
{
|
||||
-> IssueClassification {
|
||||
if ! issue.missing_number || c == '\n' {
|
||||
return IssueClassification::Bad(issue);
|
||||
} else if c == ')' {
|
||||
@ -272,10 +269,7 @@ fn find_issue() {
|
||||
#[test]
|
||||
fn issue_type() {
|
||||
let mut seeker = BadIssueSeeker::new(ReportTactic::Always, ReportTactic::Never);
|
||||
let expected = Some(Issue {
|
||||
issue_type: IssueType::Todo,
|
||||
missing_number: false
|
||||
});
|
||||
let expected = Some(Issue { issue_type: IssueType::Todo, missing_number: false });
|
||||
|
||||
assert_eq!(expected,
|
||||
"TODO(#100): more awesomeness".chars()
|
||||
@ -284,10 +278,7 @@ fn issue_type() {
|
||||
.unwrap());
|
||||
|
||||
let mut seeker = BadIssueSeeker::new(ReportTactic::Never, ReportTactic::Unnumbered);
|
||||
let expected = Some(Issue {
|
||||
issue_type: IssueType::Fixme,
|
||||
missing_number: true
|
||||
});
|
||||
let expected = Some(Issue { issue_type: IssueType::Fixme, missing_number: true });
|
||||
|
||||
assert_eq!(expected,
|
||||
"Test. FIXME: bad, bad, not good".chars()
|
||||
|
155
src/items.rs
155
src/items.rs
@ -11,7 +11,7 @@
|
||||
// Formatting top-level items - functions, structs, enums, traits, impls.
|
||||
|
||||
use {ReturnIndent, BraceStyle};
|
||||
use utils::{format_visibility, make_indent, contains_skip, span_after};
|
||||
use utils::{format_visibility, make_indent, contains_skip, span_after, end_typaram};
|
||||
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, ListTactic};
|
||||
use comment::FindUncommented;
|
||||
use visitor::FmtVisitor;
|
||||
@ -33,8 +33,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
abi: &abi::Abi,
|
||||
vis: ast::Visibility,
|
||||
span: Span)
|
||||
-> String
|
||||
{
|
||||
-> String {
|
||||
let newline_brace = self.newline_for_brace(&generics.where_clause);
|
||||
|
||||
let mut result = self.rewrite_fn_base(indent,
|
||||
@ -67,8 +66,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
ident: ast::Ident,
|
||||
sig: &ast::MethodSig,
|
||||
span: Span)
|
||||
-> String
|
||||
{
|
||||
-> String {
|
||||
// Drop semicolon or it will be interpreted as comment
|
||||
let span = codemap::mk_sp(span.lo, span.hi - BytePos(1));
|
||||
|
||||
@ -102,8 +100,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
vis: ast::Visibility,
|
||||
span: Span,
|
||||
newline_brace: bool)
|
||||
-> String
|
||||
{
|
||||
-> String {
|
||||
// FIXME we'll lose any comments in between parts of the function decl, but anyone
|
||||
// who comments there probably deserves what they get.
|
||||
|
||||
@ -160,13 +157,21 @@ impl<'a> FmtVisitor<'a> {
|
||||
result.push('(');
|
||||
}
|
||||
|
||||
// A conservative estimation, to goal is to be over all parens in generics
|
||||
let args_start = generics.ty_params
|
||||
.last()
|
||||
.map(|tp| end_typaram(tp))
|
||||
.unwrap_or(span.lo);
|
||||
let args_span = codemap::mk_sp(span_after(codemap::mk_sp(args_start, span.hi),
|
||||
"(",
|
||||
self.codemap),
|
||||
span_for_return(&fd.output).lo);
|
||||
result.push_str(&self.rewrite_args(&fd.inputs,
|
||||
explicit_self,
|
||||
one_line_budget,
|
||||
multi_line_budget,
|
||||
arg_indent,
|
||||
codemap::mk_sp(span_after(span, "(", self.codemap),
|
||||
span_for_return(&fd.output).lo)));
|
||||
args_span));
|
||||
result.push(')');
|
||||
|
||||
// Return type.
|
||||
@ -222,8 +227,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
multi_line_budget: usize,
|
||||
arg_indent: usize,
|
||||
span: Span)
|
||||
-> String
|
||||
{
|
||||
-> String {
|
||||
let mut arg_item_strs: Vec<_> = args.iter().map(|a| self.rewrite_fn_input(a)).collect();
|
||||
// Account for sugary self.
|
||||
let mut min_args = 1;
|
||||
@ -301,15 +305,13 @@ impl<'a> FmtVisitor<'a> {
|
||||
item.item = arg;
|
||||
}
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: ListTactic::HorizontalVertical,
|
||||
separator: ",",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
indent: arg_indent,
|
||||
h_width: one_line_budget,
|
||||
v_width: multi_line_budget,
|
||||
ends_with_newline: true,
|
||||
};
|
||||
let fmt = ListFormatting { tactic: ListTactic::HorizontalVertical,
|
||||
separator: ",",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
indent: arg_indent,
|
||||
h_width: one_line_budget,
|
||||
v_width: multi_line_budget,
|
||||
ends_with_newline: true, };
|
||||
|
||||
write_list(&arg_items, &fmt)
|
||||
}
|
||||
@ -319,8 +321,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
indent: usize,
|
||||
ret_str_len: usize,
|
||||
newline_brace: bool)
|
||||
-> (usize, usize, usize)
|
||||
{
|
||||
-> (usize, usize, usize) {
|
||||
let mut budgets = None;
|
||||
|
||||
// Try keeping everything on the same line
|
||||
@ -377,8 +378,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
vis: ast::Visibility,
|
||||
enum_def: &ast::EnumDef,
|
||||
generics: &ast::Generics,
|
||||
span: Span)
|
||||
{
|
||||
span: Span) {
|
||||
let header_str = self.format_header("enum ", ident, vis);
|
||||
self.changes.push_str_span(span, &header_str);
|
||||
|
||||
@ -409,18 +409,14 @@ impl<'a> FmtVisitor<'a> {
|
||||
}
|
||||
|
||||
// Variant of an enum
|
||||
fn visit_variant(&mut self,
|
||||
field: &ast::Variant,
|
||||
last_field: bool,
|
||||
next_span_start: BytePos)
|
||||
{
|
||||
fn visit_variant(&mut self, field: &ast::Variant, last_field: bool, next_span_start: BytePos) {
|
||||
if self.visit_attrs(&field.node.attrs) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.format_missing_with_indent(field.span.lo);
|
||||
|
||||
match field.node.kind {
|
||||
let result = match field.node.kind {
|
||||
ast::VariantKind::TupleVariantKind(ref types) => {
|
||||
let vis = format_visibility(field.node.vis);
|
||||
self.changes.push_str_span(field.span, vis);
|
||||
@ -475,23 +471,23 @@ impl<'a> FmtVisitor<'a> {
|
||||
"Enum variant exceeded column limit");
|
||||
}
|
||||
|
||||
self.changes.push_str_span(field.span, &result);
|
||||
|
||||
if !last_field || self.config.enum_trailing_comma {
|
||||
self.changes.push_str_span(field.span, ",");
|
||||
}
|
||||
result
|
||||
},
|
||||
ast::VariantKind::StructVariantKind(ref struct_def) => {
|
||||
let result = self.format_struct("",
|
||||
field.node.name,
|
||||
field.node.vis,
|
||||
struct_def,
|
||||
None,
|
||||
field.span,
|
||||
self.block_indent);
|
||||
|
||||
self.changes.push_str_span(field.span, &result)
|
||||
// TODO Should limit the width, as we have a trailing comma
|
||||
self.format_struct("",
|
||||
field.node.name,
|
||||
field.node.vis,
|
||||
struct_def,
|
||||
None,
|
||||
field.span,
|
||||
self.block_indent)
|
||||
}
|
||||
};
|
||||
self.changes.push_str_span(field.span, &result);
|
||||
|
||||
if !last_field || self.config.enum_trailing_comma {
|
||||
self.changes.push_str_span(field.span, ",");
|
||||
}
|
||||
|
||||
self.last_pos = field.span.hi + BytePos(1);
|
||||
@ -504,8 +500,8 @@ impl<'a> FmtVisitor<'a> {
|
||||
struct_def: &ast::StructDef,
|
||||
generics: Option<&ast::Generics>,
|
||||
span: Span,
|
||||
offset: usize) -> String
|
||||
{
|
||||
offset: usize)
|
||||
-> String {
|
||||
let mut result = String::with_capacity(1024);
|
||||
|
||||
let header_str = self.format_header(item_name, ident, vis);
|
||||
@ -557,8 +553,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
|
||||
// Conservative approximation
|
||||
let single_line_cost = (span.hi - struct_def.fields[0].span.lo).0;
|
||||
let break_line = !is_tuple ||
|
||||
generics_str.contains('\n') ||
|
||||
let break_line = !is_tuple || generics_str.contains('\n') ||
|
||||
single_line_cost as usize + used_budget > self.config.max_width;
|
||||
|
||||
if break_line {
|
||||
@ -571,15 +566,13 @@ impl<'a> FmtVisitor<'a> {
|
||||
|
||||
// 1 = ,
|
||||
let budget = self.config.ideal_width - offset + self.config.tab_spaces - 1;
|
||||
let fmt = ListFormatting {
|
||||
tactic: tactic,
|
||||
separator: ",",
|
||||
trailing_separator: self.config.struct_trailing_comma,
|
||||
indent: offset + self.config.tab_spaces,
|
||||
h_width: self.config.max_width,
|
||||
v_width: budget,
|
||||
ends_with_newline: false,
|
||||
};
|
||||
let fmt = ListFormatting { tactic: tactic,
|
||||
separator: ",",
|
||||
trailing_separator: self.config.struct_trailing_comma,
|
||||
indent: offset + self.config.tab_spaces,
|
||||
h_width: self.config.max_width,
|
||||
v_width: budget,
|
||||
ends_with_newline: false, };
|
||||
|
||||
result.push_str(&write_list(&items, &fmt));
|
||||
|
||||
@ -602,8 +595,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
vis: ast::Visibility,
|
||||
struct_def: &ast::StructDef,
|
||||
generics: &ast::Generics,
|
||||
span: Span)
|
||||
{
|
||||
span: Span) {
|
||||
let indent = self.block_indent;
|
||||
let result = self.format_struct("struct ",
|
||||
ident,
|
||||
@ -616,12 +608,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
self.last_pos = span.hi;
|
||||
}
|
||||
|
||||
fn format_header(&self,
|
||||
item_name: &str,
|
||||
ident: ast::Ident,
|
||||
vis: ast::Visibility)
|
||||
-> String
|
||||
{
|
||||
fn format_header(&self, item_name: &str, ident: ast::Ident, vis: ast::Visibility) -> String {
|
||||
format!("{}{}{}", format_visibility(vis), item_name, &token::get_ident(ident))
|
||||
}
|
||||
|
||||
@ -630,8 +617,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
opener: &str,
|
||||
offset: usize,
|
||||
span: Span)
|
||||
-> String
|
||||
{
|
||||
-> String {
|
||||
let mut result = self.rewrite_generics(generics, offset, span);
|
||||
|
||||
if generics.where_clause.predicates.len() > 0 || result.contains('\n') {
|
||||
@ -721,15 +707,13 @@ impl<'a> FmtVisitor<'a> {
|
||||
item.item = ty;
|
||||
}
|
||||
|
||||
let fmt = ListFormatting {
|
||||
tactic: ListTactic::HorizontalVertical,
|
||||
separator: ",",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
indent: offset + 1,
|
||||
h_width: budget,
|
||||
v_width: budget,
|
||||
ends_with_newline: true,
|
||||
};
|
||||
let fmt = ListFormatting { tactic: ListTactic::HorizontalVertical,
|
||||
separator: ",",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
indent: offset + 1,
|
||||
h_width: budget,
|
||||
v_width: budget,
|
||||
ends_with_newline: true, };
|
||||
result.push_str(&write_list(&items, &fmt));
|
||||
|
||||
result.push('>');
|
||||
@ -741,8 +725,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
where_clause: &ast::WhereClause,
|
||||
indent: usize,
|
||||
span_end: BytePos)
|
||||
-> String
|
||||
{
|
||||
-> String {
|
||||
let mut result = String::new();
|
||||
if where_clause.predicates.len() == 0 {
|
||||
return result;
|
||||
@ -765,15 +748,13 @@ impl<'a> FmtVisitor<'a> {
|
||||
span_end);
|
||||
|
||||
let budget = self.config.ideal_width + self.config.leeway - indent - 10;
|
||||
let fmt = ListFormatting {
|
||||
tactic: ListTactic::Vertical,
|
||||
separator: ",",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
indent: indent + 10,
|
||||
h_width: budget,
|
||||
v_width: budget,
|
||||
ends_with_newline: true,
|
||||
};
|
||||
let fmt = ListFormatting { tactic: ListTactic::Vertical,
|
||||
separator: ",",
|
||||
trailing_separator: SeparatorTactic::Never,
|
||||
indent: indent + 10,
|
||||
h_width: budget,
|
||||
v_width: budget,
|
||||
ends_with_newline: true, };
|
||||
result.push_str(&write_list(&items, &fmt));
|
||||
|
||||
result
|
||||
|
@ -167,11 +167,6 @@ impl fmt::Display for FormatReport {
|
||||
fn fmt_ast<'a>(krate: &ast::Crate, codemap: &'a CodeMap, config: &'a Config) -> ChangeSet<'a> {
|
||||
let mut visitor = FmtVisitor::from_codemap(codemap, config);
|
||||
visit::walk_crate(&mut visitor, krate);
|
||||
let files = codemap.files.borrow();
|
||||
if let Some(last) = files.last() {
|
||||
visitor.format_missing(last.end_pos);
|
||||
}
|
||||
|
||||
visitor.changes
|
||||
}
|
||||
|
||||
|
17
src/lists.rs
17
src/lists.rs
@ -48,20 +48,19 @@ pub struct ListFormatting<'a> {
|
||||
pub v_width: usize,
|
||||
// Non-expressions, e.g. items, will have a new line at the end of the list.
|
||||
// Important for comment styles.
|
||||
pub ends_with_newline: bool
|
||||
pub ends_with_newline: bool,
|
||||
}
|
||||
|
||||
pub struct ListItem {
|
||||
pub pre_comment: Option<String>,
|
||||
// Item should include attributes and doc comments
|
||||
pub item: String,
|
||||
pub post_comment: Option<String>
|
||||
pub post_comment: Option<String>,
|
||||
}
|
||||
|
||||
impl ListItem {
|
||||
pub fn is_multiline(&self) -> bool {
|
||||
self.item.contains('\n') ||
|
||||
self.pre_comment.is_some() ||
|
||||
self.item.contains('\n') || self.pre_comment.is_some() ||
|
||||
self.post_comment.as_ref().map(|s| s.contains('\n')).unwrap_or(false)
|
||||
}
|
||||
|
||||
@ -70,11 +69,7 @@ impl ListItem {
|
||||
}
|
||||
|
||||
pub fn from_str<S: Into<String>>(s: S) -> ListItem {
|
||||
ListItem {
|
||||
pre_comment: None,
|
||||
item: s.into(),
|
||||
post_comment: None
|
||||
}
|
||||
ListItem { pre_comment: None, item: s.into(), post_comment: None }
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,8 +234,8 @@ pub fn itemize_list<T, I, F1, F2, F3>(codemap: &CodeMap,
|
||||
get_item_string: F3,
|
||||
mut prev_span_end: BytePos,
|
||||
next_span_start: BytePos)
|
||||
-> Vec<ListItem>
|
||||
where I: Iterator<Item=T>,
|
||||
-> Vec<ListItem>
|
||||
where I: Iterator<Item = T>,
|
||||
F1: Fn(&T) -> BytePos,
|
||||
F2: Fn(&T) -> BytePos,
|
||||
F3: Fn(&T) -> String
|
||||
|
@ -36,8 +36,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
|
||||
fn format_missing_inner<F: Fn(&mut FmtVisitor, &str, &str, &str)>(&mut self,
|
||||
end: BytePos,
|
||||
process_last_snippet: F)
|
||||
{
|
||||
process_last_snippet: F) {
|
||||
let start = self.last_pos;
|
||||
debug!("format_missing_inner: {:?} to {:?}",
|
||||
self.codemap.lookup_char_pos(start),
|
||||
|
15
src/types.rs
15
src/types.rs
@ -15,8 +15,7 @@ use syntax::parse::token;
|
||||
use syntax::print::pprust;
|
||||
|
||||
impl<'a> FmtVisitor<'a> {
|
||||
pub fn rewrite_pred(&self, predicate: &ast::WherePredicate) -> String
|
||||
{
|
||||
pub fn rewrite_pred(&self, predicate: &ast::WherePredicate) -> String {
|
||||
// TODO dead spans
|
||||
// TODO assumes we'll always fit on one line...
|
||||
match predicate {
|
||||
@ -49,8 +48,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rewrite_lifetime_def(&self, lifetime: &ast::LifetimeDef) -> String
|
||||
{
|
||||
pub fn rewrite_lifetime_def(&self, lifetime: &ast::LifetimeDef) -> String {
|
||||
if lifetime.bounds.len() == 0 {
|
||||
return pprust::lifetime_to_string(&lifetime.lifetime);
|
||||
}
|
||||
@ -60,8 +58,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
lifetime.bounds.iter().map(|l| pprust::lifetime_to_string(l)).collect::<Vec<_>>().connect(" + "))
|
||||
}
|
||||
|
||||
pub fn rewrite_ty_bound(&self, bound: &ast::TyParamBound) -> String
|
||||
{
|
||||
pub fn rewrite_ty_bound(&self, bound: &ast::TyParamBound) -> String {
|
||||
match *bound {
|
||||
ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::None) => {
|
||||
self.rewrite_poly_trait_ref(tref)
|
||||
@ -75,8 +72,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rewrite_ty_param(&self, ty_param: &ast::TyParam) -> String
|
||||
{
|
||||
pub fn rewrite_ty_param(&self, ty_param: &ast::TyParam) -> String {
|
||||
let mut result = String::with_capacity(128);
|
||||
result.push_str(&token::get_ident(ty_param.ident));
|
||||
if ty_param.bounds.len() > 0 {
|
||||
@ -91,8 +87,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
result
|
||||
}
|
||||
|
||||
fn rewrite_poly_trait_ref(&self, t: &ast::PolyTraitRef) -> String
|
||||
{
|
||||
fn rewrite_poly_trait_ref(&self, t: &ast::PolyTraitRef) -> String {
|
||||
if t.bound_lifetimes.len() > 0 {
|
||||
format!("for<{}> {}",
|
||||
t.bound_lifetimes.iter().map(|l| self.rewrite_lifetime_def(l)).collect::<Vec<_>>().connect(", "),
|
||||
|
10
src/utils.rs
10
src/utils.rs
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use syntax::ast::{Visibility, Attribute, MetaItem, MetaItem_};
|
||||
use syntax::ast::{self, Visibility, Attribute, MetaItem, MetaItem_};
|
||||
use syntax::codemap::{CodeMap, Span, BytePos};
|
||||
|
||||
use comment::FindUncommented;
|
||||
@ -72,6 +72,14 @@ pub fn contains_skip(attrs: &[Attribute]) -> bool {
|
||||
attrs.iter().any(|a| is_skip(&a.node.value))
|
||||
}
|
||||
|
||||
// Find the end of a TyParam
|
||||
pub fn end_typaram(typaram: &ast::TyParam) -> BytePos {
|
||||
typaram.bounds.last().map(|bound| match *bound {
|
||||
ast::RegionTyParamBound(ref lt) => lt.span,
|
||||
ast::TraitTyParamBound(ref prt, _) => prt.span,
|
||||
}).unwrap_or(typaram.span).hi
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(target_pointer_width="64")]
|
||||
// Based on the trick layed out at
|
||||
|
108
src/visitor.rs
108
src/visitor.rs
@ -11,9 +11,13 @@
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{self, CodeMap, Span, BytePos};
|
||||
use syntax::visit;
|
||||
use syntax::parse::token;
|
||||
use syntax::attr;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use utils;
|
||||
use config::Config;
|
||||
use comment::FindUncommented;
|
||||
|
||||
use changes::ChangeSet;
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
@ -197,7 +201,6 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
|
||||
visit::walk_item(self, item);
|
||||
}
|
||||
ast::Item_::ItemImpl(..) |
|
||||
ast::Item_::ItemMod(_) |
|
||||
ast::Item_::ItemTrait(..) => {
|
||||
self.block_indent += self.config.tab_spaces;
|
||||
visit::walk_item(self, item);
|
||||
@ -227,6 +230,10 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
|
||||
item.span);
|
||||
self.last_pos = item.span.hi;
|
||||
}
|
||||
ast::Item_::ItemMod(ref module) => {
|
||||
self.format_missing_with_indent(item.span.lo);
|
||||
self.format_mod(module, item.span, item.ident, &item.attrs);
|
||||
}
|
||||
_ => {
|
||||
visit::walk_item(self, item);
|
||||
}
|
||||
@ -267,24 +274,19 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
|
||||
}
|
||||
|
||||
fn visit_mod(&mut self, m: &'v ast::Mod, s: Span, _: ast::NodeId) {
|
||||
// Only visit inline mods here.
|
||||
if self.codemap.lookup_char_pos(s.lo).file.name !=
|
||||
self.codemap.lookup_char_pos(m.inner.lo).file.name {
|
||||
return;
|
||||
}
|
||||
visit::walk_mod(self, m);
|
||||
// This is only called for the root module
|
||||
let filename = self.codemap.span_to_filename(s);
|
||||
self.format_separate_mod(m, &filename);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FmtVisitor<'a> {
|
||||
pub fn from_codemap<'b>(codemap: &'b CodeMap, config: &'b Config) -> FmtVisitor<'b> {
|
||||
FmtVisitor {
|
||||
codemap: codemap,
|
||||
changes: ChangeSet::from_codemap(codemap),
|
||||
last_pos: BytePos(0),
|
||||
block_indent: 0,
|
||||
config: config
|
||||
}
|
||||
FmtVisitor { codemap: codemap,
|
||||
changes: ChangeSet::from_codemap(codemap),
|
||||
last_pos: BytePos(0),
|
||||
block_indent: 0,
|
||||
config: config, }
|
||||
}
|
||||
|
||||
pub fn snippet(&self, span: Span) -> String {
|
||||
@ -352,4 +354,82 @@ impl<'a> FmtVisitor<'a> {
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn format_mod(&mut self, m: &ast::Mod, s: Span, ident: ast::Ident, attrs: &[ast::Attribute]) {
|
||||
debug!("FmtVisitor::format_mod: ident: {:?}, span: {:?}", ident, s);
|
||||
// Decide whether this is an inline mod or an external mod.
|
||||
// There isn't any difference between inline and external mod in AST,
|
||||
// so we use the trick of searching for an opening brace.
|
||||
// We can't use the inner span of the mod since it is weird when it
|
||||
// is empty (no items).
|
||||
// FIXME Use the inner span once rust-lang/rust#26755 is fixed.
|
||||
let open_brace = self.codemap.span_to_snippet(s).unwrap().find_uncommented("{");
|
||||
match open_brace {
|
||||
None => {
|
||||
debug!("FmtVisitor::format_mod: external mod");
|
||||
let file_path = self.module_file(ident, attrs, s);
|
||||
let filename = file_path.to_str().unwrap();
|
||||
if self.changes.is_changed(filename) {
|
||||
// The file has already been reformatted, do nothing
|
||||
} else {
|
||||
self.format_separate_mod(m, filename);
|
||||
}
|
||||
// TODO Should rewrite properly `mod X;`
|
||||
}
|
||||
Some(open_brace) => {
|
||||
debug!("FmtVisitor::format_mod: internal mod");
|
||||
debug!("... open_brace: {}, str: {:?}", open_brace, self.codemap.span_to_snippet(s));
|
||||
// Format everything until opening brace
|
||||
// TODO Shoud rewrite properly
|
||||
self.format_missing(s.lo + BytePos(open_brace as u32));
|
||||
self.block_indent += self.config.tab_spaces;
|
||||
visit::walk_mod(self, m);
|
||||
debug!("... last_pos after: {:?}", self.last_pos);
|
||||
self.block_indent -= self.config.tab_spaces;
|
||||
}
|
||||
}
|
||||
self.format_missing(s.hi);
|
||||
debug!("FmtVisitor::format_mod: exit");
|
||||
}
|
||||
|
||||
/// Find the file corresponding to an external mod
|
||||
/// Same algorithm as syntax::parse::eval_src_mod
|
||||
fn module_file(&self, id: ast::Ident, outer_attrs: &[ast::Attribute], id_sp: Span) -> PathBuf {
|
||||
// FIXME use libsyntax once rust-lang/rust#26750 is merged
|
||||
let mut prefix = PathBuf::from(&self.codemap.span_to_filename(id_sp));
|
||||
prefix.pop();
|
||||
let mod_string = token::get_ident(id);
|
||||
match attr::first_attr_value_str_by_name(outer_attrs, "path") {
|
||||
Some(d) => prefix.join(&*d),
|
||||
None => {
|
||||
let default_path_str = format!("{}.rs", mod_string);
|
||||
let secondary_path_str = format!("{}/mod.rs", mod_string);
|
||||
let default_path = prefix.join(&default_path_str);
|
||||
let secondary_path = prefix.join(&secondary_path_str);
|
||||
let default_exists = self.codemap.file_exists(&default_path);
|
||||
let secondary_exists = self.codemap.file_exists(&secondary_path);
|
||||
if default_exists {
|
||||
default_path
|
||||
} else if secondary_exists {
|
||||
secondary_path
|
||||
} else {
|
||||
// Should never appens since rustc parsed everything sucessfully
|
||||
panic!("Didn't found module {}", mod_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Format the content of a module into a separate file
|
||||
fn format_separate_mod(&mut self, m: &ast::Mod, filename: &str) {
|
||||
let last_pos = self.last_pos;
|
||||
let block_indent = self.block_indent;
|
||||
let filemap = self.codemap.get_filemap(filename);
|
||||
self.last_pos = filemap.start_pos;
|
||||
self.block_indent = 0;
|
||||
visit::walk_mod(self, m);
|
||||
self.format_missing(filemap.end_pos);
|
||||
self.last_pos = last_pos;
|
||||
self.block_indent = block_indent;
|
||||
}
|
||||
}
|
||||
|
3
tests/source/mod-2.rs
Normal file
3
tests/source/mod-2.rs
Normal file
@ -0,0 +1,3 @@
|
||||
// Some nested mods
|
||||
|
||||
mod nestedmod;
|
12
tests/source/nestedmod/mod.rs
Normal file
12
tests/source/nestedmod/mod.rs
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
mod mod2a;
|
||||
mod mod2b;
|
||||
|
||||
mod mymod1 {
|
||||
use mod2a::{Foo,Bar};
|
||||
}
|
||||
|
||||
#[path="mod2c.rs"]
|
||||
mod mymod2;
|
||||
|
||||
mod submod2;
|
4
tests/source/nestedmod/mod2a.rs
Normal file
4
tests/source/nestedmod/mod2a.rs
Normal file
@ -0,0 +1,4 @@
|
||||
// This is an empty file containing only
|
||||
// comments
|
||||
|
||||
// ...................
|
3
tests/source/nestedmod/mod2b.rs
Normal file
3
tests/source/nestedmod/mod2b.rs
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
#[path="mod2a.rs"]
|
||||
mod c;
|
3
tests/source/nestedmod/mod2c.rs
Normal file
3
tests/source/nestedmod/mod2c.rs
Normal file
@ -0,0 +1,3 @@
|
||||
// A standard mod
|
||||
|
||||
fn a( ) {}
|
6
tests/source/nestedmod/submod2/a.rs
Normal file
6
tests/source/nestedmod/submod2/a.rs
Normal file
@ -0,0 +1,6 @@
|
||||
// Yet Another mod
|
||||
// Nested
|
||||
|
||||
use c::a;
|
||||
|
||||
fn foo( ) { }
|
5
tests/source/nestedmod/submod2/mod.rs
Normal file
5
tests/source/nestedmod/submod2/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
// Another mod
|
||||
|
||||
mod a;
|
||||
|
||||
use a::a;
|
@ -40,5 +40,8 @@ enum StructLikeVariants {
|
||||
// Pre-comment
|
||||
#[Attr50]
|
||||
y: SomeType, // Aanother Comment
|
||||
}
|
||||
},
|
||||
SL {
|
||||
a: A,
|
||||
},
|
||||
}
|
||||
|
@ -34,6 +34,9 @@ fn foo<U, T>(a: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,
|
||||
|
||||
}
|
||||
|
||||
fn foo<U: Fn(A) -> B /* paren inside generics */>() {
|
||||
}
|
||||
|
||||
impl Foo {
|
||||
fn with_no_errors<T, F>(&mut self, f: F) -> T
|
||||
where F: FnOnce(&mut Resolver) -> T
|
||||
|
3
tests/target/mod-2.rs
Normal file
3
tests/target/mod-2.rs
Normal file
@ -0,0 +1,3 @@
|
||||
// Some nested mods
|
||||
|
||||
mod nestedmod;
|
12
tests/target/nestedmod/mod.rs
Normal file
12
tests/target/nestedmod/mod.rs
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
mod mod2a;
|
||||
mod mod2b;
|
||||
|
||||
mod mymod1 {
|
||||
use mod2a::{Foo, Bar};
|
||||
}
|
||||
|
||||
#[path="mod2c.rs"]
|
||||
mod mymod2;
|
||||
|
||||
mod submod2;
|
4
tests/target/nestedmod/mod2a.rs
Normal file
4
tests/target/nestedmod/mod2a.rs
Normal file
@ -0,0 +1,4 @@
|
||||
// This is an empty file containing only
|
||||
// comments
|
||||
|
||||
// ...................
|
3
tests/target/nestedmod/mod2b.rs
Normal file
3
tests/target/nestedmod/mod2b.rs
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
#[path="mod2a.rs"]
|
||||
mod c;
|
4
tests/target/nestedmod/mod2c.rs
Normal file
4
tests/target/nestedmod/mod2c.rs
Normal file
@ -0,0 +1,4 @@
|
||||
// A standard mod
|
||||
|
||||
fn a() {
|
||||
}
|
7
tests/target/nestedmod/submod2/a.rs
Normal file
7
tests/target/nestedmod/submod2/a.rs
Normal file
@ -0,0 +1,7 @@
|
||||
// Yet Another mod
|
||||
// Nested
|
||||
|
||||
use c::a;
|
||||
|
||||
fn foo() {
|
||||
}
|
5
tests/target/nestedmod/submod2/mod.rs
Normal file
5
tests/target/nestedmod/submod2/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
// Another mod
|
||||
|
||||
mod a;
|
||||
|
||||
use a::a;
|
Loading…
Reference in New Issue
Block a user