diff --git a/Cargo.toml b/Cargo.toml index 3c8b758d53dca..d23d681df00c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ filetime = "0.2" rustc-workspace-hack = "1.0" # UI test dependencies +clap = { version = "3.1", features = ["derive"] } clippy_utils = { path = "clippy_utils" } derive-new = "0.5" if_chain = "1.0" diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 3de91f3d24a91..7105ce4b292ae 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -585,15 +585,21 @@ impl EarlyLintPass for EarlyAttributes { } fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { - for attr in &item.attrs { + let mut iter = item.attrs.iter().peekable(); + while let Some(attr) = iter.next() { if matches!(attr.kind, AttrKind::Normal(..)) && attr.style == AttrStyle::Outer && is_present_in_source(cx, attr.span) { let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent()); - let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt(), item.span.parent()); + let end_of_attr_to_next_attr_or_item = Span::new( + attr.span.hi(), + iter.peek().map_or(item.span.lo(), |next_attr| next_attr.span.lo()), + item.span.ctxt(), + item.span.parent(), + ); - if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) { + if let Some(snippet) = snippet_opt(cx, end_of_attr_to_next_attr_or_item) { let lines = snippet.split('\n').collect::>(); let lines = without_block_comments(lines); @@ -623,8 +629,15 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Opti if feature_item.has_name(sym::rustfmt); // check for `rustfmt_skip` and `rustfmt::skip` if let Some(skip_item) = &items[1].meta_item(); - if skip_item.has_name(sym!(rustfmt_skip)) || - skip_item.path.segments.last().expect("empty path in attribute").ident.name == sym::skip; + if skip_item.has_name(sym!(rustfmt_skip)) + || skip_item + .path + .segments + .last() + .expect("empty path in attribute") + .ident + .name + == sym::skip; // Only lint outer attributes, because custom inner attributes are unstable // Tracking issue: https://github.com/rust-lang/rust/issues/54726 if attr.style == AttrStyle::Outer; diff --git a/tests/compile-test.rs b/tests/compile-test.rs index c9710e3db8e8d..18099c45fee3c 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -22,6 +22,7 @@ const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal"); /// All crates used in UI tests are listed here static TEST_DEPENDENCIES: &[&str] = &[ + "clap", "clippy_utils", "derive_new", "futures", @@ -40,6 +41,8 @@ static TEST_DEPENDENCIES: &[&str] = &[ // Test dependencies may need an `extern crate` here to ensure that they show up // in the depinfo file (otherwise cargo thinks they are unused) #[allow(unused_extern_crates)] +extern crate clap; +#[allow(unused_extern_crates)] extern crate clippy_utils; #[allow(unused_extern_crates)] extern crate derive_new; @@ -109,8 +112,9 @@ static EXTERN_FLAGS: SyncLazy = SyncLazy::new(|| { not_found.is_empty(), "dependencies not found in depinfo: {:?}\n\ help: Make sure the `-Z binary-dep-depinfo` rust flag is enabled\n\ - help: Try adding to dev-dependencies in Cargo.toml", - not_found + help: Try adding to dev-dependencies in Cargo.toml\n\ + help: Be sure to also add `extern crate ...;` to tests/compile-test.rs", + not_found, ); crates .into_iter() diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs index 3e92bca986ab5..d15c84d7438a0 100644 --- a/tests/ui/empty_line_after_outer_attribute.rs +++ b/tests/ui/empty_line_after_outer_attribute.rs @@ -4,6 +4,9 @@ #![feature(custom_inner_attributes)] #![rustfmt::skip] +#[macro_use] +extern crate clap; + #[macro_use] extern crate proc_macro_attr; @@ -110,4 +113,11 @@ pub trait Bazz { } } +#[derive(clap::Parser)] +#[clap(after_help = "This ia a help message. + +You're welcome. +")] +pub struct Args; + fn main() {} diff --git a/tests/ui/empty_line_after_outer_attribute.stderr b/tests/ui/empty_line_after_outer_attribute.stderr index 594fca44a3210..acc3edef9b928 100644 --- a/tests/ui/empty_line_after_outer_attribute.stderr +++ b/tests/ui/empty_line_after_outer_attribute.stderr @@ -1,5 +1,5 @@ error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:11:1 + --> $DIR/empty_line_after_outer_attribute.rs:14:1 | LL | / #[crate_type = "lib"] LL | | @@ -10,7 +10,7 @@ LL | | fn with_one_newline_and_comment() { assert!(true) } = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings` error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:23:1 + --> $DIR/empty_line_after_outer_attribute.rs:26:1 | LL | / #[crate_type = "lib"] LL | | @@ -18,7 +18,7 @@ LL | | fn with_one_newline() { assert!(true) } | |_ error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:28:1 + --> $DIR/empty_line_after_outer_attribute.rs:31:1 | LL | / #[crate_type = "lib"] LL | | @@ -27,7 +27,7 @@ LL | | fn with_two_newlines() { assert!(true) } | |_ error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:35:1 + --> $DIR/empty_line_after_outer_attribute.rs:38:1 | LL | / #[crate_type = "lib"] LL | | @@ -35,7 +35,7 @@ LL | | enum Baz { | |_ error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:43:1 + --> $DIR/empty_line_after_outer_attribute.rs:46:1 | LL | / #[crate_type = "lib"] LL | | @@ -43,7 +43,7 @@ LL | | struct Foo { | |_ error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute? - --> $DIR/empty_line_after_outer_attribute.rs:51:1 + --> $DIR/empty_line_after_outer_attribute.rs:54:1 | LL | / #[crate_type = "lib"] LL | |