Skip to content

Commit

Permalink
Use contiguous spans for empty_line_after_* suggestion
Browse files Browse the repository at this point in the history
Replacing an empty span (which an empty line is) with an empty string triggers a
debug assertion in rustc. This fixes the debug assertion by using contiguous
spans, with the same resulting suggestion.
  • Loading branch information
flip1995 committed Sep 23, 2024
1 parent 43e3384 commit 5636f07
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 3 deletions.
31 changes: 29 additions & 2 deletions clippy_lints/src/doc/empty_line_after.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_errors::{Applicability, Diag, SuggestionStyle};
use rustc_hir::{ItemKind, Node};
use rustc_lexer::TokenKind;
use rustc_lint::LateContext;
use rustc_span::{ExpnKind, InnerSpan, Span, SpanData};
use rustc_span::{BytePos, ExpnKind, InnerSpan, Span, SpanData};

use super::{EMPTY_LINE_AFTER_DOC_COMMENTS, EMPTY_LINE_AFTER_OUTER_ATTR};

Expand Down Expand Up @@ -144,6 +144,30 @@ impl<'a> Gap<'a> {
prev_chunk,
})
}

fn contiguous_empty_lines(&self) -> Vec<Span> {
let mut spans = Vec::new();

let mut prev_span = *self.empty_lines.first().expect("at least one empty line");

// The BytePos subtraction here is safe, as before an empty line, there must be at least one
// attribute/comment.
prev_span = prev_span.with_lo(prev_span.lo() - BytePos(1));
for empty_line in &self.empty_lines {
if empty_line.lo() - prev_span.hi() > BytePos(1) {
// If the empty line doesn't immidiately follow the previous one, push the previous span...
spans.push(prev_span);
// ...and start a new one
prev_span = empty_line.with_lo(empty_line.lo() - BytePos(1));
} else {
// Otherwise, extend the previous span
prev_span = prev_span.with_hi(empty_line.hi());
}
}
spans.push(prev_span);

spans
}
}

/// If the node the attributes/docs apply to is the first in the module/crate suggest converting
Expand Down Expand Up @@ -192,6 +216,7 @@ fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool {
return false;
};
let empty_lines = || gaps.iter().flat_map(|gap| gap.empty_lines.iter().copied());
let contiguous_empty_lines = || gaps.iter().flat_map(Gap::contiguous_empty_lines);
let mut has_comment = false;
let mut has_attr = false;
for gap in gaps {
Expand Down Expand Up @@ -227,7 +252,9 @@ fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool {

diag.multipart_suggestion_with_style(
format!("if the empty {lines} {are} unintentional remove {them}"),
empty_lines().map(|empty_line| (empty_line, String::new())).collect(),
contiguous_empty_lines()
.map(|empty_lines| (empty_lines, String::new()))
.collect(),
Applicability::MaybeIncorrect,
SuggestionStyle::HideCodeAlways,
);
Expand Down
5 changes: 5 additions & 0 deletions tests/ui/empty_line_after/outer_attribute.1.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ mod foo {}
// Still lint cases where the empty line does not immediately follow the attribute
fn comment_before_empty_line() {}

//~v empty_line_after_outer_attr
#[allow(unused)]
// This comment is isolated
pub fn isolated_comment() {}

#[doc = "
Returns the escaped value of the textual representation of
Expand Down
5 changes: 5 additions & 0 deletions tests/ui/empty_line_after/outer_attribute.2.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ mod foo {}
// Still lint cases where the empty line does not immediately follow the attribute
fn comment_before_empty_line() {}

//~v empty_line_after_outer_attr
#[allow(unused)]
// This comment is isolated
pub fn isolated_comment() {}

#[doc = "
Returns the escaped value of the textual representation of
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/empty_line_after/outer_attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ mod foo {}

fn comment_before_empty_line() {}

//~v empty_line_after_outer_attr
#[allow(unused)]

// This comment is isolated

pub fn isolated_comment() {}

#[doc = "
Returns the escaped value of the textual representation of
Expand Down
15 changes: 14 additions & 1 deletion tests/ui/empty_line_after/outer_attribute.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,18 @@ LL | fn comment_before_empty_line() {}
|
= help: if the empty line is unintentional remove it

error: aborting due to 8 previous errors
error: empty lines after outer attribute
--> tests/ui/empty_line_after/outer_attribute.rs:64:1
|
LL | / #[allow(unused)]
LL | |
LL | | // This comment is isolated
LL | |
| |_
LL | pub fn isolated_comment() {}
| ------------------------- the attribute applies to this function
|
= help: if the empty lines are unintentional remove them

error: aborting due to 9 previous errors

0 comments on commit 5636f07

Please sign in to comment.