Skip to content

Commit 62dc7c5

Browse files
fix: inner attribute formatting
1 parent 89b7f5f commit 62dc7c5

File tree

4 files changed

+98
-59
lines changed

4 files changed

+98
-59
lines changed

src/formatting.rs

+7-22
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use self::newline_style::apply_newline_style;
1111
use crate::comment::{CharClasses, FullCodeCharKind};
1212
use crate::config::{Config, FileName, Verbosity};
1313
use crate::issues::BadIssueSeeker;
14+
use crate::modules::Module;
1415
use crate::syntux::parser::{DirectoryOwnership, Parser, ParserError};
1516
use crate::syntux::session::ParseSess;
1617
use crate::utils::count_newlines;
@@ -102,8 +103,7 @@ fn format_project<T: FormatHandler>(
102103
continue;
103104
}
104105
should_emit_verbose(input_is_stdin, config, || println!("Formatting {}", path));
105-
let is_root = path == main_file;
106-
context.format_file(path, &module, is_root)?;
106+
context.format_file(path, &module)?;
107107
}
108108
timer = timer.done_formatting();
109109

@@ -134,13 +134,8 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
134134
}
135135

136136
// Formats a single file/module.
137-
fn format_file(
138-
&mut self,
139-
path: FileName,
140-
module: &ast::Mod,
141-
is_root: bool,
142-
) -> Result<(), ErrorKind> {
143-
let snippet_provider = self.parse_session.snippet_provider(module.inner);
137+
fn format_file(&mut self, path: FileName, module: &Module<'_>) -> Result<(), ErrorKind> {
138+
let snippet_provider = self.parse_session.snippet_provider(module.as_ref().inner);
144139
let mut visitor = FmtVisitor::from_parse_sess(
145140
&self.parse_session,
146141
&self.config,
@@ -149,19 +144,9 @@ impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
149144
);
150145
visitor.skip_context.update_with_attrs(&self.krate.attrs);
151146

152-
// Format inner attributes if available.
153-
if !self.krate.attrs.is_empty() && is_root {
154-
visitor.skip_empty_lines(snippet_provider.end_pos());
155-
if visitor.visit_attrs(&self.krate.attrs, ast::AttrStyle::Inner) {
156-
visitor.push_rewrite(module.inner, None);
157-
} else {
158-
visitor.format_separate_mod(module, snippet_provider.end_pos());
159-
}
160-
} else {
161-
visitor.last_pos = snippet_provider.start_pos();
162-
visitor.skip_empty_lines(snippet_provider.end_pos());
163-
visitor.format_separate_mod(module, snippet_provider.end_pos());
164-
};
147+
visitor.last_pos = snippet_provider.start_pos();
148+
visitor.skip_empty_lines(snippet_provider.end_pos());
149+
visitor.format_separate_mod(module, snippet_provider.end_pos());
165150

166151
debug_assert_eq!(
167152
visitor.line_number,

src/modules.rs

+82-31
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::collections::BTreeMap;
33
use std::path::{Path, PathBuf};
44

55
use rustc_ast::ast;
6+
use rustc_ast::attr::HasAttrs;
67
use rustc_ast::visit::Visitor;
78
use rustc_span::symbol::{self, sym, Symbol};
89
use thiserror::Error;
@@ -18,12 +19,48 @@ use crate::utils::contains_skip;
1819

1920
mod visitor;
2021

21-
type FileModMap<'ast> = BTreeMap<FileName, Cow<'ast, ast::Mod>>;
22+
type FileModMap<'ast> = BTreeMap<FileName, Module<'ast>>;
2223

2324
lazy_static! {
2425
static ref CFG_IF: Symbol = Symbol::intern("cfg_if");
2526
}
2627

28+
/// Represents module with its inner attributes.
29+
#[derive(Debug, Clone)]
30+
pub(crate) struct Module<'a> {
31+
ast_mod: Cow<'a, ast::Mod>,
32+
inner_attr: Vec<ast::Attribute>,
33+
}
34+
35+
impl<'a> Module<'a> {
36+
pub(crate) fn new(ast_mod: Cow<'a, ast::Mod>, attrs: &[ast::Attribute]) -> Self {
37+
let inner_attr = attrs
38+
.iter()
39+
.filter(|attr| attr.style == ast::AttrStyle::Inner)
40+
.cloned()
41+
.collect();
42+
Module {
43+
ast_mod,
44+
inner_attr,
45+
}
46+
}
47+
}
48+
49+
impl<'a> HasAttrs for Module<'a> {
50+
fn attrs(&self) -> &[ast::Attribute] {
51+
&self.inner_attr
52+
}
53+
fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<ast::Attribute>)) {
54+
f(&mut self.inner_attr)
55+
}
56+
}
57+
58+
impl<'a> AsRef<ast::Mod> for Module<'a> {
59+
fn as_ref(&self) -> &ast::Mod {
60+
&self.ast_mod
61+
}
62+
}
63+
2764
/// Maps each module to the corresponding file.
2865
pub(crate) struct ModResolver<'ast, 'sess> {
2966
parse_sess: &'sess ParseSess,
@@ -53,9 +90,9 @@ pub(crate) enum ModuleResolutionErrorKind {
5390
#[derive(Clone)]
5491
enum SubModKind<'a, 'ast> {
5592
/// `mod foo;`
56-
External(PathBuf, DirectoryOwnership, Cow<'ast, ast::Mod>),
93+
External(PathBuf, DirectoryOwnership, Module<'ast>),
5794
/// `mod foo;` with multiple sources.
58-
MultiExternal(Vec<(PathBuf, DirectoryOwnership, Cow<'ast, ast::Mod>)>),
95+
MultiExternal(Vec<(PathBuf, DirectoryOwnership, Module<'ast>)>),
5996
/// `mod foo {}`
6097
Internal(&'a ast::Item),
6198
}
@@ -94,8 +131,10 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
94131
self.visit_mod_from_ast(&krate.module)?;
95132
}
96133

97-
self.file_map
98-
.insert(root_filename, Cow::Borrowed(&krate.module));
134+
self.file_map.insert(
135+
root_filename,
136+
Module::new(Cow::Borrowed(&krate.module), &krate.attrs),
137+
);
99138
Ok(self.file_map)
100139
}
101140

@@ -105,7 +144,10 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
105144
visitor.visit_item(&item);
106145
for module_item in visitor.mods() {
107146
if let ast::ItemKind::Mod(ref sub_mod) = module_item.item.kind {
108-
self.visit_sub_mod(&module_item.item, Cow::Owned(sub_mod.clone()))?;
147+
self.visit_sub_mod(
148+
&module_item.item,
149+
Module::new(Cow::Owned(sub_mod.clone()), &module_item.item.attrs),
150+
)?;
109151
}
110152
}
111153
Ok(())
@@ -120,7 +162,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
120162
}
121163

122164
if let ast::ItemKind::Mod(ref sub_mod) = item.kind {
123-
self.visit_sub_mod(&item, Cow::Owned(sub_mod.clone()))?;
165+
self.visit_sub_mod(&item, Module::new(Cow::Owned(sub_mod.clone()), &item.attrs))?;
124166
}
125167
}
126168
Ok(())
@@ -134,7 +176,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
134176
}
135177

136178
if let ast::ItemKind::Mod(ref sub_mod) = item.kind {
137-
self.visit_sub_mod(item, Cow::Borrowed(sub_mod))?;
179+
self.visit_sub_mod(item, Module::new(Cow::Borrowed(sub_mod), &item.attrs))?;
138180
}
139181
}
140182
Ok(())
@@ -143,12 +185,12 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
143185
fn visit_sub_mod(
144186
&mut self,
145187
item: &'c ast::Item,
146-
sub_mod: Cow<'ast, ast::Mod>,
188+
sub_mod: Module<'ast>,
147189
) -> Result<(), ModuleResolutionError> {
148190
let old_directory = self.directory.clone();
149191
let sub_mod_kind = self.peek_sub_mod(item, &sub_mod)?;
150192
if let Some(sub_mod_kind) = sub_mod_kind {
151-
self.insert_sub_mod(sub_mod_kind.clone(), sub_mod.clone())?;
193+
self.insert_sub_mod(sub_mod_kind.clone())?;
152194
self.visit_sub_mod_inner(sub_mod, sub_mod_kind)?;
153195
}
154196
self.directory = old_directory;
@@ -159,7 +201,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
159201
fn peek_sub_mod(
160202
&self,
161203
item: &'c ast::Item,
162-
sub_mod: &Cow<'ast, ast::Mod>,
204+
sub_mod: &Module<'ast>,
163205
) -> Result<Option<SubModKind<'c, 'ast>>, ModuleResolutionError> {
164206
if contains_skip(&item.attrs) {
165207
return Ok(None);
@@ -178,7 +220,6 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
178220
fn insert_sub_mod(
179221
&mut self,
180222
sub_mod_kind: SubModKind<'c, 'ast>,
181-
_sub_mod: Cow<'ast, ast::Mod>,
182223
) -> Result<(), ModuleResolutionError> {
183224
match sub_mod_kind {
184225
SubModKind::External(mod_path, _, sub_mod) => {
@@ -200,7 +241,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
200241

201242
fn visit_sub_mod_inner(
202243
&mut self,
203-
sub_mod: Cow<'ast, ast::Mod>,
244+
sub_mod: Module<'ast>,
204245
sub_mod_kind: SubModKind<'c, 'ast>,
205246
) -> Result<(), ModuleResolutionError> {
206247
match sub_mod_kind {
@@ -230,13 +271,13 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
230271

231272
fn visit_sub_mod_after_directory_update(
232273
&mut self,
233-
sub_mod: Cow<'ast, ast::Mod>,
274+
sub_mod: Module<'ast>,
234275
directory: Option<Directory>,
235276
) -> Result<(), ModuleResolutionError> {
236277
if let Some(directory) = directory {
237278
self.directory = directory;
238279
}
239-
match sub_mod {
280+
match sub_mod.ast_mod {
240281
Cow::Borrowed(sub_mod) => self.visit_mod_from_ast(sub_mod),
241282
Cow::Owned(sub_mod) => self.visit_mod_outside_ast(sub_mod),
242283
}
@@ -247,7 +288,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
247288
&self,
248289
mod_name: symbol::Ident,
249290
attrs: &[ast::Attribute],
250-
sub_mod: &Cow<'ast, ast::Mod>,
291+
sub_mod: &Module<'ast>,
251292
) -> Result<Option<SubModKind<'c, 'ast>>, ModuleResolutionError> {
252293
let relative = match self.directory.ownership {
253294
DirectoryOwnership::Owned { relative } => relative,
@@ -257,12 +298,13 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
257298
if self.parse_sess.is_file_parsed(&path) {
258299
return Ok(None);
259300
}
260-
return match Parser::parse_file_as_module(self.parse_sess, &path, sub_mod.inner) {
301+
return match Parser::parse_file_as_module(self.parse_sess, &path, sub_mod.ast_mod.inner)
302+
{
261303
Ok((_, ref attrs)) if contains_skip(attrs) => Ok(None),
262-
Ok((m, _)) => Ok(Some(SubModKind::External(
304+
Ok(m) => Ok(Some(SubModKind::External(
263305
path,
264306
DirectoryOwnership::Owned { relative: None },
265-
Cow::Owned(m),
307+
Module::new(Cow::Owned(m.0), &m.1),
266308
))),
267309
Err(ParserError::ParseError) => Err(ModuleResolutionError {
268310
module: mod_name.to_string(),
@@ -300,13 +342,19 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
300342
return Ok(Some(SubModKind::MultiExternal(mods_outside_ast)));
301343
}
302344
}
303-
match Parser::parse_file_as_module(self.parse_sess, &path, sub_mod.inner) {
345+
match Parser::parse_file_as_module(self.parse_sess, &path, sub_mod.ast_mod.inner) {
304346
Ok((_, ref attrs)) if contains_skip(attrs) => Ok(None),
305-
Ok((m, _)) if outside_mods_empty => {
306-
Ok(Some(SubModKind::External(path, ownership, Cow::Owned(m))))
307-
}
308-
Ok((m, _)) => {
309-
mods_outside_ast.push((path.clone(), ownership, Cow::Owned(m)));
347+
Ok(m) if outside_mods_empty => Ok(Some(SubModKind::External(
348+
path,
349+
ownership,
350+
Module::new(Cow::Owned(m.0), &m.1),
351+
))),
352+
Ok(m) => {
353+
mods_outside_ast.push((
354+
path.clone(),
355+
ownership,
356+
Module::new(Cow::Owned(m.0), &m.1),
357+
));
310358
if should_insert {
311359
mods_outside_ast.push((path, ownership, sub_mod.clone()));
312360
}
@@ -368,8 +416,8 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
368416
fn find_mods_outside_of_ast(
369417
&self,
370418
attrs: &[ast::Attribute],
371-
sub_mod: &Cow<'ast, ast::Mod>,
372-
) -> Vec<(PathBuf, DirectoryOwnership, Cow<'ast, ast::Mod>)> {
419+
sub_mod: &Module<'ast>,
420+
) -> Vec<(PathBuf, DirectoryOwnership, Module<'ast>)> {
373421
// Filter nested path, like `#[cfg_attr(feature = "foo", path = "bar.rs")]`.
374422
let mut path_visitor = visitor::PathVisitor::default();
375423
for attr in attrs.iter() {
@@ -393,17 +441,20 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
393441
));
394442
continue;
395443
}
396-
let m = match Parser::parse_file_as_module(self.parse_sess, &actual_path, sub_mod.inner)
397-
{
444+
let m = match Parser::parse_file_as_module(
445+
self.parse_sess,
446+
&actual_path,
447+
sub_mod.ast_mod.inner,
448+
) {
398449
Ok((_, ref attrs)) if contains_skip(attrs) => continue,
399-
Ok((m, _)) => m,
450+
Ok(m) => m,
400451
Err(..) => continue,
401452
};
402453

403454
result.push((
404455
actual_path,
405456
DirectoryOwnership::Owned { relative: None },
406-
Cow::Owned(m),
457+
Module::new(Cow::Owned(m.0), &m.1),
407458
))
408459
}
409460
result

src/visitor.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::cell::{Cell, RefCell};
22
use std::rc::Rc;
33

4-
use rustc_ast::{ast, token::DelimToken, visit};
4+
use rustc_ast::{ast, attr::HasAttrs, token::DelimToken, visit};
55
use rustc_span::{symbol, BytePos, Pos, Span};
66

77
use crate::attr::*;
@@ -16,6 +16,7 @@ use crate::items::{
1616
StaticParts, StructParts,
1717
};
1818
use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition};
19+
use crate::modules::Module;
1920
use crate::rewrite::{Rewrite, RewriteContext};
2021
use crate::shape::{Indent, Shape};
2122
use crate::skip::{is_skip_attr, SkipContext};
@@ -938,10 +939,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
938939
}
939940
}
940941

941-
pub(crate) fn format_separate_mod(&mut self, m: &ast::Mod, end_pos: BytePos) {
942+
pub(crate) fn format_separate_mod(&mut self, m: &Module<'_>, end_pos: BytePos) {
942943
self.block_indent = Indent::empty();
943-
self.walk_mod_items(m);
944-
self.format_missing_with_indent(end_pos);
944+
if self.visit_attrs(m.attrs(), ast::AttrStyle::Inner) {
945+
self.push_skipped_with_span(m.attrs(), m.as_ref().inner, m.as_ref().inner);
946+
} else {
947+
self.walk_mod_items(m.as_ref());
948+
self.format_missing_with_indent(end_pos);
949+
}
945950
}
946951

947952
pub(crate) fn skip_empty_lines(&mut self, end_pos: BytePos) {

tests/target/inner-module-path/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// rustfmt-recursive: true
2-
31
#[path = "."]
42
mod a {
53
mod b;

0 commit comments

Comments
 (0)