Skip to content

Commit 2b8d4fd

Browse files
authored
Format inner attributes (#4207)
2 parents 3eb864e + 6b1063d commit 2b8d4fd

File tree

7 files changed

+116
-131
lines changed

7 files changed

+116
-131
lines changed

rustfmt-core/rustfmt-lib/src/formatting.rs

+6-19
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub(crate) use syntux::session::ParseSess;
99

1010
use self::newline_style::apply_newline_style;
1111
use crate::config::{Config, FileName};
12+
use crate::formatting::modules::Module;
1213
use crate::formatting::{
1314
comment::{CharClasses, FullCodeCharKind},
1415
report::NonFormattedRange,
@@ -127,14 +128,12 @@ fn format_project(
127128
should_emit_verbose(input_is_stdin, operation_setting.verbosity, || {
128129
println!("Formatting {}", path)
129130
});
130-
let is_root = path == main_file;
131131
format_file(
132132
&parse_session,
133133
config,
134134
&krate,
135135
path,
136136
&module,
137-
is_root,
138137
&format_report,
139138
original_snippet.clone(),
140139
);
@@ -157,29 +156,17 @@ fn format_file(
157156
config: &Config,
158157
krate: &ast::Crate,
159158
path: FileName,
160-
module: &ast::Mod,
161-
is_root: bool,
159+
module: &Module<'_>,
162160
report: &FormatReport,
163161
original_snippet: Option<String>,
164162
) {
165-
let snippet_provider = parse_session.snippet_provider(module.inner);
163+
let snippet_provider = parse_session.snippet_provider(module.as_ref().inner);
166164
let mut visitor =
167165
FmtVisitor::from_parse_sess(&parse_session, config, &snippet_provider, report.clone());
168166
visitor.skip_context.update_with_attrs(&krate.attrs);
169-
170-
// Format inner attributes if available.
171-
if !krate.attrs.is_empty() && is_root {
172-
visitor.skip_empty_lines(snippet_provider.end_pos());
173-
if visitor.visit_attrs(&krate.attrs, ast::AttrStyle::Inner) {
174-
visitor.push_rewrite(module.inner, None);
175-
} else {
176-
visitor.format_separate_mod(module, snippet_provider.end_pos());
177-
}
178-
} else {
179-
visitor.last_pos = snippet_provider.start_pos();
180-
visitor.skip_empty_lines(snippet_provider.end_pos());
181-
visitor.format_separate_mod(module, snippet_provider.end_pos());
182-
};
167+
visitor.last_pos = snippet_provider.start_pos();
168+
visitor.skip_empty_lines(snippet_provider.end_pos());
169+
visitor.format_separate_mod(module, snippet_provider.end_pos());
183170

184171
debug_assert_eq!(
185172
visitor.line_number,

rustfmt-core/rustfmt-lib/src/formatting/modules.rs

+79-28
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::formatting::{
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,11 +298,12 @@ 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(m) => Ok(Some(SubModKind::External(
262304
path,
263305
DirectoryOwnership::Owned { relative: None },
264-
Cow::Owned(m),
306+
Module::new(Cow::Owned(m.0), &m.1),
265307
))),
266308
Err(ParserError::ParseError) => Err(ModuleResolutionError {
267309
module: mod_name.to_string(),
@@ -299,12 +341,18 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
299341
return Ok(Some(SubModKind::MultiExternal(mods_outside_ast)));
300342
}
301343
}
302-
match Parser::parse_file_as_module(self.parse_sess, &path, sub_mod.inner) {
303-
Ok(m) if outside_mods_empty => {
304-
Ok(Some(SubModKind::External(path, ownership, Cow::Owned(m))))
305-
}
344+
match Parser::parse_file_as_module(self.parse_sess, &path, sub_mod.ast_mod.inner) {
345+
Ok(m) if outside_mods_empty => Ok(Some(SubModKind::External(
346+
path,
347+
ownership,
348+
Module::new(Cow::Owned(m.0), &m.1),
349+
))),
306350
Ok(m) => {
307-
mods_outside_ast.push((path.clone(), ownership, Cow::Owned(m)));
351+
mods_outside_ast.push((
352+
path.clone(),
353+
ownership,
354+
Module::new(Cow::Owned(m.0), &m.1),
355+
));
308356
if should_insert {
309357
mods_outside_ast.push((path, ownership, sub_mod.clone()));
310358
}
@@ -366,8 +414,8 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
366414
fn find_mods_outside_of_ast(
367415
&self,
368416
attrs: &[ast::Attribute],
369-
sub_mod: &Cow<'ast, ast::Mod>,
370-
) -> Vec<(PathBuf, DirectoryOwnership, Cow<'ast, ast::Mod>)> {
417+
sub_mod: &Module<'ast>,
418+
) -> Vec<(PathBuf, DirectoryOwnership, Module<'ast>)> {
371419
// Filter nested path, like `#[cfg_attr(feature = "foo", path = "bar.rs")]`.
372420
let mut path_visitor = visitor::PathVisitor::default();
373421
for attr in attrs.iter() {
@@ -394,16 +442,19 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
394442
continue;
395443
}
396444

397-
let m = match Parser::parse_file_as_module(self.parse_sess, &actual_path, sub_mod.inner)
398-
{
445+
let m = match Parser::parse_file_as_module(
446+
self.parse_sess,
447+
&actual_path,
448+
sub_mod.ast_mod.inner,
449+
) {
399450
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

0 commit comments

Comments
 (0)