- let (first_group_len, first_group_str) = rewrite_first_group_attrs(context, self, shape)?;
- if self.len() == 1 || first_group_len == self.len() {
- Some(first_group_str)
- } else {
- let rest_str = self[first_group_len..].rewrite(context, shape)?;
- let missing_span = mk_sp(
- self[first_group_len - 1].span.hi(),
- self[first_group_len].span.lo(),
- );
- // Preserve an empty line before/after doc comments.
- if self[0].is_sugared_doc || self[first_group_len].is_sugared_doc {
- let snippet = context.snippet(missing_span);
- let (mla, mlb) = has_newlines_before_after_comment(snippet);
+
+ // The current remaining attributes.
+ let mut attrs = self;
+ let mut result = String::new();
+
+ // This is not just a simple map because we need to handle doc comments
+ // (where we take as many doc comment attributes as possible) and possibly
+ // merging derives into a single attribute.
+ loop {
+ if attrs.is_empty() {
+ return Some(result);
+ }
+
+ // Handle doc comments.
+ let (doc_comment_len, doc_comment_str) =
+ rewrite_initial_doc_comments(context, attrs, shape)?;
+ if doc_comment_len > 0 {
+ let doc_comment_str = doc_comment_str.expect("doc comments, but no result");
+ result.push_str(&doc_comment_str);
+
+ let missing_span = attrs
+ .get(doc_comment_len)
+ .map(|next| mk_sp(attrs[doc_comment_len - 1].span.hi(), next.span.lo()));
+ if let Some(missing_span) = missing_span {
+ let snippet = context.snippet(missing_span);
+ let (mla, mlb) = has_newlines_before_after_comment(snippet);
+ let comment = ::comment::recover_missing_comment_in_span(
+ missing_span,
+ shape.with_max_width(context.config),
+ context,
+ 0,
+ )?;
+ let comment = if comment.is_empty() {
+ format!("\n{}", mlb)
+ } else {
+ format!("{}{}\n{}", mla, comment, mlb)
+ };
+ result.push_str(&comment);
+ result.push_str(&shape.indent.to_string(context.config));
+ }
+
+ attrs = &attrs[doc_comment_len..];
+
+ continue;
+ }
+
+ // Handle derives if we will merge them.
+ if context.config.merge_derives() && is_derive(&attrs[0]) {
+ let derives = take_while_with_pred(context, attrs, is_derive);
+ let mut derive_spans = vec![];
+ for derive in derives {
+ derive_spans.append(&mut get_derive_spans(derive)?);
+ }
+ let derive_str =
+ format_derive(&derive_spans, attr_prefix(&attrs[0]), shape, context)?;
+ result.push_str(&derive_str);
+
+ let missing_span = attrs
+ .get(derives.len())
+ .map(|next| mk_sp(attrs[derives.len() - 1].span.hi(), next.span.lo()));
+ if let Some(missing_span) = missing_span {
+ let comment = ::comment::recover_missing_comment_in_span(
+ missing_span,
+ shape.with_max_width(context.config),
+ context,
+ 0,
+ )?;
+ result.push_str(&comment);
+ if let Some(next) = attrs.get(derives.len()) {
+ if next.is_sugared_doc {
+ let snippet = context.snippet(missing_span);
+ let (_, mlb) = has_newlines_before_after_comment(snippet);
+ result.push_str(&mlb);
+ }
+ }
+ result.push('\n');
+ result.push_str(&shape.indent.to_string(context.config));
+ }
+
+ attrs = &attrs[derives.len()..];
+
+ continue;
+ }
+
+ // If we get here, then we have a regular attribute, just handle one
+ // at a time.
+
+ let formatted_attr = attrs[0].rewrite(context, shape)?;
+ result.push_str(&formatted_attr);
+
+ let missing_span = attrs
+ .get(1)
+ .map(|next| mk_sp(attrs[0].span.hi(), next.span.lo()));
+ if let Some(missing_span) = missing_span {