refactor: apply rustc mod parsing changes

This commit is contained in:
Caleb Cartwright 2021-03-28 16:25:30 -05:00 committed by Caleb Cartwright
parent 2c6339571b
commit 612e8d5b9b
5 changed files with 130 additions and 70 deletions

View File

@ -145,7 +145,7 @@ fn format_file(
module: &Module<'_>,
is_macro_def: bool,
) -> Result<(), ErrorKind> {
let snippet_provider = self.parse_session.snippet_provider(module.as_ref().inner);
let snippet_provider = self.parse_session.snippet_provider(module.span);
let mut visitor = FmtVisitor::from_parse_sess(
&self.parse_session,
&self.config,

View File

@ -3271,8 +3271,8 @@ pub(crate) fn rewrite_extern_crate(
/// Returns `true` for `mod foo;`, false for `mod foo { .. }`.
pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
match item.kind {
ast::ItemKind::Mod(ref m) => m.inner.hi() != item.span.hi(),
_ => false,
ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _)) => false,
_ => true,
}
}

View File

@ -6,6 +6,7 @@
use rustc_ast::attr::HasAttrs;
use rustc_ast::visit::Visitor;
use rustc_span::symbol::{self, sym, Symbol};
use rustc_span::Span;
use thiserror::Error;
use crate::attr::MetaVisitor;
@ -24,20 +25,31 @@
/// Represents module with its inner attributes.
#[derive(Debug, Clone)]
pub(crate) struct Module<'a> {
ast_mod: Cow<'a, ast::Mod>,
ast_mod_kind: Option<Cow<'a, ast::ModKind>>,
pub(crate) items: Cow<'a, Vec<rustc_ast::ptr::P<ast::Item>>>,
attrs: Cow<'a, Vec<ast::Attribute>>,
inner_attr: Vec<ast::Attribute>,
pub(crate) span: Span,
}
impl<'a> Module<'a> {
pub(crate) fn new(ast_mod: Cow<'a, ast::Mod>, attrs: &[ast::Attribute]) -> Self {
let inner_attr = attrs
pub(crate) fn new(
mod_span: Span,
ast_mod_kind: Option<Cow<'a, ast::ModKind>>,
mod_items: Cow<'a, Vec<rustc_ast::ptr::P<ast::Item>>>,
mod_attrs: Cow<'a, Vec<ast::Attribute>>,
) -> Self {
let inner_attr = mod_attrs
.iter()
.filter(|attr| attr.style == ast::AttrStyle::Inner)
.cloned()
.collect();
Module {
ast_mod,
items: mod_items,
attrs: mod_attrs,
inner_attr,
span: mod_span,
ast_mod_kind,
}
}
}
@ -51,12 +63,6 @@ fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<ast::Attribute>)) {
}
}
impl<'a> AsRef<ast::Mod> for Module<'a> {
fn as_ref(&self) -> &ast::Mod {
&self.ast_mod
}
}
/// Maps each module to the corresponding file.
pub(crate) struct ModResolver<'ast, 'sess> {
parse_sess: &'sess ParseSess,
@ -124,12 +130,17 @@ pub(crate) fn visit_crate(
// Skip visiting sub modules when the input is from stdin.
if self.recursive {
self.visit_mod_from_ast(&krate.module)?;
self.visit_mod_from_ast(&krate.items)?;
}
self.file_map.insert(
root_filename,
Module::new(Cow::Borrowed(&krate.module), &krate.attrs),
Module::new(
krate.span,
None,
Cow::Borrowed(&krate.items),
Cow::Borrowed(&krate.attrs),
),
);
Ok(self.file_map)
}
@ -139,10 +150,15 @@ fn visit_cfg_if(&mut self, item: Cow<'ast, ast::Item>) -> Result<(), ModuleResol
let mut visitor = visitor::CfgIfVisitor::new(self.parse_sess);
visitor.visit_item(&item);
for module_item in visitor.mods() {
if let ast::ItemKind::Mod(ref sub_mod) = module_item.item.kind {
if let ast::ItemKind::Mod(_, ref sub_mod_kind) = module_item.item.kind {
self.visit_sub_mod(
&module_item.item,
Module::new(Cow::Owned(sub_mod.clone()), &module_item.item.attrs),
Module::new(
module_item.item.span,
Some(Cow::Owned(sub_mod_kind.clone())),
Cow::Owned(vec![]),
Cow::Owned(vec![]),
),
)?;
}
}
@ -150,29 +166,53 @@ fn visit_cfg_if(&mut self, item: Cow<'ast, ast::Item>) -> Result<(), ModuleResol
}
/// Visit modules defined inside macro calls.
fn visit_mod_outside_ast(&mut self, module: ast::Mod) -> Result<(), ModuleResolutionError> {
for item in module.items {
fn visit_mod_outside_ast(
&mut self,
items: Vec<rustc_ast::ptr::P<ast::Item>>,
) -> Result<(), ModuleResolutionError> {
for item in items {
if is_cfg_if(&item) {
self.visit_cfg_if(Cow::Owned(item.into_inner()))?;
continue;
}
if let ast::ItemKind::Mod(ref sub_mod) = item.kind {
self.visit_sub_mod(&item, Module::new(Cow::Owned(sub_mod.clone()), &item.attrs))?;
if let ast::ItemKind::Mod(_, ref sub_mod_kind) = item.kind {
let span = item.span;
self.visit_sub_mod(
&item,
Module::new(
span,
Some(Cow::Owned(sub_mod_kind.clone())),
Cow::Owned(vec![]),
Cow::Owned(vec![]),
),
)?;
}
}
Ok(())
}
/// Visit modules from AST.
fn visit_mod_from_ast(&mut self, module: &'ast ast::Mod) -> Result<(), ModuleResolutionError> {
for item in &module.items {
fn visit_mod_from_ast(
&mut self,
items: &'ast Vec<rustc_ast::ptr::P<ast::Item>>,
) -> Result<(), ModuleResolutionError> {
for item in items {
if is_cfg_if(item) {
self.visit_cfg_if(Cow::Borrowed(item))?;
}
if let ast::ItemKind::Mod(ref sub_mod) = item.kind {
self.visit_sub_mod(item, Module::new(Cow::Borrowed(sub_mod), &item.attrs))?;
if let ast::ItemKind::Mod(_, ref sub_mod_kind) = item.kind {
let span = item.span;
self.visit_sub_mod(
item,
Module::new(
span,
Some(Cow::Borrowed(sub_mod_kind)),
Cow::Owned(vec![]),
Cow::Borrowed(&item.attrs),
),
)?;
}
}
Ok(())
@ -273,9 +313,12 @@ fn visit_sub_mod_after_directory_update(
if let Some(directory) = directory {
self.directory = directory;
}
match sub_mod.ast_mod {
Cow::Borrowed(sub_mod) => self.visit_mod_from_ast(sub_mod),
Cow::Owned(sub_mod) => self.visit_mod_outside_ast(sub_mod),
match (sub_mod.ast_mod_kind, sub_mod.items) {
(Some(Cow::Borrowed(ast::ModKind::Loaded(items, ast::Inline::No, _))), _) => {
self.visit_mod_from_ast(&items)
}
(Some(Cow::Owned(..)), Cow::Owned(items)) => self.visit_mod_outside_ast(items),
(_, _) => Ok(()),
}
}
@ -294,13 +337,17 @@ fn find_external_module(
if self.parse_sess.is_file_parsed(&path) {
return Ok(None);
}
return match Parser::parse_file_as_module(self.parse_sess, &path, sub_mod.ast_mod.inner)
{
Ok((_, ref attrs)) if contains_skip(attrs) => Ok(None),
Ok(m) => Ok(Some(SubModKind::External(
return match Parser::parse_file_as_module(self.parse_sess, &path, sub_mod.span) {
Ok((ref attrs, _, _)) if contains_skip(attrs) => Ok(None),
Ok((attrs, items, span)) => Ok(Some(SubModKind::External(
path,
DirectoryOwnership::Owned { relative: None },
Module::new(Cow::Owned(m.0), &m.1),
Module::new(
span,
Some(Cow::Owned(ast::ModKind::Unloaded)),
Cow::Owned(items),
Cow::Owned(attrs),
),
))),
Err(ParserError::ParseError) => Err(ModuleResolutionError {
module: mod_name.to_string(),
@ -338,18 +385,30 @@ fn find_external_module(
return Ok(Some(SubModKind::MultiExternal(mods_outside_ast)));
}
}
match Parser::parse_file_as_module(self.parse_sess, &path, sub_mod.ast_mod.inner) {
Ok((_, ref attrs)) if contains_skip(attrs) => Ok(None),
Ok(m) if outside_mods_empty => Ok(Some(SubModKind::External(
path,
ownership,
Module::new(Cow::Owned(m.0), &m.1),
))),
Ok(m) => {
match Parser::parse_file_as_module(self.parse_sess, &path, sub_mod.span) {
Ok((ref attrs, _, _)) if contains_skip(attrs) => Ok(None),
Ok((attrs, items, span)) if outside_mods_empty => {
Ok(Some(SubModKind::External(
path,
ownership,
Module::new(
span,
Some(Cow::Owned(ast::ModKind::Unloaded)),
Cow::Owned(items),
Cow::Owned(attrs),
),
)))
}
Ok((attrs, items, span)) => {
mods_outside_ast.push((
path.clone(),
ownership,
Module::new(Cow::Owned(m.0), &m.1),
Module::new(
span,
Some(Cow::Owned(ast::ModKind::Unloaded)),
Cow::Owned(items),
Cow::Owned(attrs),
),
));
if should_insert {
mods_outside_ast.push((path, ownership, sub_mod.clone()));
@ -437,20 +496,22 @@ fn find_mods_outside_of_ast(
));
continue;
}
let m = match Parser::parse_file_as_module(
self.parse_sess,
&actual_path,
sub_mod.ast_mod.inner,
) {
Ok((_, ref attrs)) if contains_skip(attrs) => continue,
Ok(m) => m,
Err(..) => continue,
};
let (attrs, items, span) =
match Parser::parse_file_as_module(self.parse_sess, &actual_path, sub_mod.span) {
Ok((ref attrs, _, _)) if contains_skip(attrs) => continue,
Ok(m) => m,
Err(..) => continue,
};
result.push((
actual_path,
DirectoryOwnership::Owned { relative: None },
Module::new(Cow::Owned(m.0), &m.1),
Module::new(
span,
Some(Cow::Owned(ast::ModKind::Unloaded)),
Cow::Owned(items),
Cow::Owned(attrs),
),
))
}
result

View File

@ -1,8 +1,8 @@
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::path::{Path, PathBuf};
use rustc_ast::ast;
use rustc_ast::token::{DelimToken, TokenKind};
use rustc_ast::{ast, ptr};
use rustc_errors::Diagnostic;
use rustc_parse::{
new_parser_from_file,
@ -109,10 +109,10 @@ pub(crate) fn parse_file_as_module(
sess: &'a ParseSess,
path: &Path,
span: Span,
) -> Result<(ast::Mod, Vec<ast::Attribute>), ParserError> {
) -> Result<(Vec<ast::Attribute>, Vec<ptr::P<ast::Item>>, Span), ParserError> {
let result = catch_unwind(AssertUnwindSafe(|| {
let mut parser = new_parser_from_file(sess.inner(), &path, Some(span));
match parser.parse_mod(&TokenKind::Eof, ast::Unsafe::No) {
match parser.parse_mod(&TokenKind::Eof) {
Ok(result) => Some(result),
Err(mut e) => {
sess.emit_or_cancel_diagnostic(&mut e);

View File

@ -524,10 +524,9 @@ pub(crate) fn visit_item(&mut self, item: &ast::Item) {
self.visit_enum(item.ident, &item.vis, def, generics, item.span);
self.last_pos = source!(self, item.span).hi();
}
ast::ItemKind::Mod(ref module) => {
let is_inline = !is_mod_decl(item);
ast::ItemKind::Mod(unsafety, ref mod_kind) => {
self.format_missing_with_indent(source!(self, item.span).lo());
self.format_mod(module, &item.vis, item.span, item.ident, attrs, is_inline);
self.format_mod(mod_kind, unsafety, &item.vis, item.span, item.ident, attrs);
}
ast::ItemKind::MacCall(ref mac) => {
self.visit_mac(mac, Some(item.ident), MacroPosition::Item);
@ -921,8 +920,8 @@ fn is_unknown_rustfmt_attr(&self, segments: &[ast::PathSegment]) -> bool {
!is_skip_attr(segments)
}
fn walk_mod_items(&mut self, m: &ast::Mod) {
self.visit_items_with_reordering(&ptr_vec_to_ref_vec(&m.items));
fn walk_mod_items(&mut self, items: &Vec<rustc_ast::ptr::P<ast::Item>>) {
self.visit_items_with_reordering(&ptr_vec_to_ref_vec(&items));
}
fn walk_stmts(&mut self, stmts: &[Stmt<'_>], include_current_empty_semi: bool) {
@ -974,22 +973,22 @@ fn walk_block_stmts(&mut self, b: &ast::Block) {
fn format_mod(
&mut self,
m: &ast::Mod,
mod_kind: &ast::ModKind,
unsafety: ast::Unsafe,
vis: &ast::Visibility,
s: Span,
ident: symbol::Ident,
attrs: &[ast::Attribute],
is_internal: bool,
) {
let vis_str = utils::format_visibility(&self.get_context(), vis);
self.push_str(&*vis_str);
self.push_str(format_unsafety(m.unsafety));
self.push_str(format_unsafety(unsafety));
self.push_str("mod ");
// 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 {
if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, inner_span) = mod_kind {
match self.config.brace_style() {
BraceStyle::AlwaysNextLine => {
let indent_str = self.block_indent.to_string_with_newline(self.config);
@ -1001,7 +1000,7 @@ fn format_mod(
// Hackery to account for the closing }.
let mod_lo = self.snippet_provider.span_after(source!(self, s), "{");
let body_snippet =
self.snippet(mk_sp(mod_lo, source!(self, m.inner).hi() - BytePos(1)));
self.snippet(mk_sp(mod_lo, source!(self, inner_span).hi() - BytePos(1)));
let body_snippet = body_snippet.trim();
if body_snippet.is_empty() {
self.push_str("}");
@ -1009,11 +1008,11 @@ fn format_mod(
self.last_pos = mod_lo;
self.block_indent = self.block_indent.block_indent(self.config);
self.visit_attrs(attrs, ast::AttrStyle::Inner);
self.walk_mod_items(m);
let missing_span = self.next_span(m.inner.hi() - BytePos(1));
self.walk_mod_items(items);
let missing_span = self.next_span(inner_span.hi() - BytePos(1));
self.close_block(missing_span, false);
}
self.last_pos = source!(self, m.inner).hi();
self.last_pos = source!(self, inner_span).hi();
} else {
self.push_str(";");
self.last_pos = source!(self, s).hi();
@ -1023,9 +1022,9 @@ fn format_mod(
pub(crate) fn format_separate_mod(&mut self, m: &Module<'_>, end_pos: BytePos) {
self.block_indent = Indent::empty();
if self.visit_attrs(m.attrs(), ast::AttrStyle::Inner) {
self.push_skipped_with_span(m.attrs(), m.as_ref().inner, m.as_ref().inner);
self.push_skipped_with_span(m.attrs(), m.span, m.span);
} else {
self.walk_mod_items(m.as_ref());
self.walk_mod_items(&m.items);
self.format_missing_with_indent(end_pos);
}
}