Skip to content

Commit d6b088e

Browse files
committed
refactor MetaItem formatting
so that we can experiment with new formatting rules for long lines
1 parent 0415e86 commit d6b088e

File tree

1 file changed

+89
-43
lines changed

1 file changed

+89
-43
lines changed

src/tools/rustfmt/src/attr.rs

Lines changed: 89 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -249,12 +249,7 @@ impl Rewrite for ast::MetaItemInner {
249249
}
250250

251251
fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
252-
match self {
253-
ast::MetaItemInner::MetaItem(ref meta_item) => meta_item.rewrite_result(context, shape),
254-
ast::MetaItemInner::Lit(ref l) => {
255-
rewrite_literal(context, l.as_token_lit(), l.span, shape)
256-
}
257-
}
252+
rewrite_meta_item_inner_result(self, context, shape, false)
258253
}
259254
}
260255

@@ -283,45 +278,96 @@ impl Rewrite for ast::MetaItem {
283278
}
284279

285280
fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
286-
Ok(match self.kind {
287-
ast::MetaItemKind::Word => {
288-
rewrite_path(context, PathContext::Type, &None, &self.path, shape)?
289-
}
290-
ast::MetaItemKind::List(ref list) => {
291-
let path = rewrite_path(context, PathContext::Type, &None, &self.path, shape)?;
292-
let has_trailing_comma = crate::expr::span_ends_with_comma(context, self.span);
293-
overflow::rewrite_with_parens(
294-
context,
295-
&path,
296-
list.iter(),
297-
// 1 = "]"
298-
shape.sub_width(1).max_width_error(shape.width, self.span)?,
299-
self.span,
300-
context.config.attr_fn_like_width(),
301-
Some(if has_trailing_comma {
302-
SeparatorTactic::Always
281+
rewrite_meta_item_result(self, context, shape, false)
282+
}
283+
}
284+
285+
pub(crate) fn rewrite_meta_item_inner_result(
286+
this: &ast::MetaItemInner,
287+
context: &RewriteContext<'_>,
288+
shape: Shape,
289+
line_break_list: bool,
290+
) -> RewriteResult {
291+
match this {
292+
ast::MetaItemInner::MetaItem(ref meta_item) => {
293+
rewrite_meta_item_result(meta_item, context, shape, line_break_list)
294+
}
295+
ast::MetaItemInner::Lit(ref l) => rewrite_literal(context, l.as_token_lit(), l.span, shape),
296+
}
297+
}
298+
299+
pub(crate) fn rewrite_meta_item_result(
300+
this: &ast::MetaItem,
301+
context: &RewriteContext<'_>,
302+
shape: Shape,
303+
line_break_list: bool,
304+
) -> RewriteResult {
305+
let path = rewrite_path(context, PathContext::Type, &None, &this.path, shape)?;
306+
307+
match this.kind {
308+
ast::MetaItemKind::Word => {
309+
// E.g., `#[test]`, which lacks any arguments after `test`.
310+
Ok(path)
311+
}
312+
ast::MetaItemKind::List(ref list) => {
313+
// E.g., `#[derive(..)]`, where the `list` represents the `..`.
314+
315+
let separator_tactic = if crate::expr::span_ends_with_comma(context, this.span) {
316+
SeparatorTactic::Always
317+
} else {
318+
SeparatorTactic::Never
319+
};
320+
321+
overflow::rewrite_with_parens(
322+
context,
323+
&path,
324+
list.iter(),
325+
shape
326+
.sub_width("]".len())
327+
.max_width_error(shape.width, this.span)?,
328+
this.span,
329+
context.config.attr_fn_like_width(),
330+
Some(separator_tactic),
331+
)
332+
}
333+
ast::MetaItemKind::NameValue(ref lit) => {
334+
// E.g., `#[feature = "foo"]`, where the `lit` represents the `"foo"`.
335+
336+
let lit_shape = shape
337+
.shrink_left(path.len() + " = ".len())
338+
.max_width_error(shape.width, this.span)?;
339+
340+
// `rewrite_literal` returns `None` when `lit` exceeds max
341+
// width. Since a literal is basically unformattable unless it
342+
// is a string literal (and only if `format_strings` is set),
343+
// we might be better off ignoring the fact that the attribute
344+
// is longer than the max width and continue on formatting.
345+
// See #2479 for example.
346+
347+
match rewrite_literal(context, lit.as_token_lit(), lit.span, lit_shape) {
348+
Ok(value) => {
349+
// The whole meta item fits on one line.
350+
Ok(format!("{path} = {value}"))
351+
}
352+
Err(_) => {
353+
// `lit` exceeded the maximum width of its Shape.
354+
if line_break_list {
355+
// Insert a line break before the `=`.
356+
let mut result = String::new();
357+
result.push_str(&path);
358+
result.push_str(&shape.indent.to_string_with_newline(context.config));
359+
result.push_str("= ");
360+
result.push_str(context.snippet(lit.span));
361+
362+
Ok(result)
303363
} else {
304-
SeparatorTactic::Never
305-
}),
306-
)?
307-
}
308-
ast::MetaItemKind::NameValue(ref lit) => {
309-
let path = rewrite_path(context, PathContext::Type, &None, &self.path, shape)?;
310-
// 3 = ` = `
311-
let lit_shape = shape
312-
.shrink_left(path.len() + 3)
313-
.max_width_error(shape.width, self.span)?;
314-
// `rewrite_literal` returns `None` when `lit` exceeds max
315-
// width. Since a literal is basically unformattable unless it
316-
// is a string literal (and only if `format_strings` is set),
317-
// we might be better off ignoring the fact that the attribute
318-
// is longer than the max width and continue on formatting.
319-
// See #2479 for example.
320-
let value = rewrite_literal(context, lit.as_token_lit(), lit.span, lit_shape)
321-
.unwrap_or_else(|_| context.snippet(lit.span).to_owned());
322-
format!("{path} = {value}")
364+
// Just format on a single line anyway.
365+
let value = context.snippet(lit.span);
366+
Ok(format!("{path} = {value}"))
367+
}
368+
}
323369
}
324-
})
370+
}
325371
}
326372
}
327373

0 commit comments

Comments
 (0)