Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make empty_line_after_outer_attr an early lint #5609

Merged
merged 4 commits into from May 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -32,6 +32,8 @@ semver = "0.9.0"
# NOTE: cargo requires serde feat in its url dep
# see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864>
url = { version = "2.1.0", features = ["serde"] }
quote = "1"
syn = { version = "1", features = ["full"] }

[features]
deny-warnings = []
@@ -248,7 +248,6 @@ declare_lint_pass!(Attributes => [
INLINE_ALWAYS,
DEPRECATED_SEMVER,
USELESS_ATTRIBUTE,
EMPTY_LINE_AFTER_OUTER_ATTR,
UNKNOWN_CLIPPY_LINTS,
]);

@@ -480,36 +479,6 @@ fn check_attrs(cx: &LateContext<'_, '_>, span: Span, name: Name, attrs: &[Attrib
}

for attr in attrs {
let attr_item = if let AttrKind::Normal(ref attr) = attr.kind {
attr
} else {
continue;
};

if attr.style == AttrStyle::Outer {
if attr_item.args.inner_tokens().is_empty() || !is_present_in_source(cx, attr.span) {
return;
}

let begin_of_attr_to_item = Span::new(attr.span.lo(), span.lo(), span.ctxt());
let end_of_attr_to_item = Span::new(attr.span.hi(), span.lo(), span.ctxt());

if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) {
let lines = snippet.split('\n').collect::<Vec<_>>();
let lines = without_block_comments(lines);

if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 {
span_lint(
cx,
EMPTY_LINE_AFTER_OUTER_ATTR,
begin_of_attr_to_item,
"Found an empty line after an outer attribute. \
Perhaps you forgot to add a `!` to make it an inner attribute?",
);
}
}
}

if let Some(values) = attr.meta_item_list() {
if values.len() != 1 || !attr.check_name(sym!(inline)) {
continue;
@@ -551,15 +520,57 @@ fn is_word(nmi: &NestedMetaItem, expected: Symbol) -> bool {
}
}

declare_lint_pass!(EarlyAttributes => [DEPRECATED_CFG_ATTR, MISMATCHED_TARGET_OS]);
declare_lint_pass!(EarlyAttributes => [
DEPRECATED_CFG_ATTR,
MISMATCHED_TARGET_OS,
EMPTY_LINE_AFTER_OUTER_ATTR,
]);

impl EarlyLintPass for EarlyAttributes {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::ast::Item) {
check_empty_line_after_outer_attr(cx, item);
}

fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
check_deprecated_cfg_attr(cx, attr);
check_mismatched_target_os(cx, attr);
}
}

fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::ast::Item) {
for attr in &item.attrs {
let attr_item = if let AttrKind::Normal(ref attr) = attr.kind {
attr
} else {
return;
};

if attr.style == AttrStyle::Outer {
if attr_item.args.inner_tokens().is_empty() || !is_present_in_source(cx, attr.span) {
return;
}

let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt());
let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt());

if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) {
let lines = snippet.split('\n').collect::<Vec<_>>();
let lines = without_block_comments(lines);

if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 {
span_lint(
cx,
EMPTY_LINE_AFTER_OUTER_ATTR,
begin_of_attr_to_item,
"Found an empty line after an outer attribute. \
Perhaps you forgot to add a `!` to make it an inner attribute?",
);
}
}
}
}
}

fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) {
if_chain! {
// check cfg_attr
@@ -38,7 +38,7 @@ fn clippy_driver_path() -> PathBuf {
// as what we manually pass to `cargo` invocation
fn third_party_crates() -> String {
use std::collections::HashMap;
static CRATES: &[&str] = &["serde", "serde_derive", "regex", "clippy_lints"];
static CRATES: &[&str] = &["serde", "serde_derive", "regex", "clippy_lints", "syn", "quote"];
let dep_dir = cargo::TARGET_LIB.join("deps");
let mut crates: HashMap<&str, PathBuf> = HashMap::with_capacity(CRATES.len());
for entry in fs::read_dir(dep_dir).unwrap() {
@@ -0,0 +1,37 @@
// no-prefer-dynamic

#![crate_type = "proc-macro"]
#![feature(repr128, proc_macro_hygiene, proc_macro_quote)]
#![allow(clippy::useless_conversion)]

extern crate proc_macro;
extern crate quote;
extern crate syn;

use proc_macro::TokenStream;
use quote::{quote, quote_spanned};
use syn::parse_macro_input;
use syn::{parse_quote, ItemTrait, TraitItem};

#[proc_macro_attribute]
pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream {
let mut item = parse_macro_input!(input as ItemTrait);
for inner in &mut item.items {
if let TraitItem::Method(method) = inner {
let sig = &method.sig;
let block = &mut method.default;
if let Some(block) = block {
let brace = block.brace_token;

let my_block = quote_spanned!( brace.span => {
// Should not trigger `empty_line_after_outer_attr`
#[crate_type = "lib"]
#sig #block
Vec::new()
});
*block = parse_quote!(#my_block);
}
}
}
TokenStream::from(quote!(#item))
}
@@ -1,8 +1,12 @@
// aux-build:proc_macro_attr.rs
#![warn(clippy::empty_line_after_outer_attr)]
#![allow(clippy::assertions_on_constants)]
#![feature(custom_inner_attributes)]
#![rustfmt::skip]

#[macro_use]
extern crate proc_macro_attr;

// This should produce a warning
#[crate_type = "lib"]

@@ -93,4 +97,17 @@ pub struct S;
/* test */
pub struct T;

fn main() { }
// This should not produce a warning
// See https://github.com/rust-lang/rust-clippy/issues/5567
#[fake_async_trait]
pub trait Bazz {
fn foo() -> Vec<u8> {
let _i = "";



vec![]
}
}

fn main() {}
@@ -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:7:1
--> $DIR/empty_line_after_outer_attribute.rs:11:1
|
LL | / #[crate_type = "lib"]
LL | |
@@ -10,15 +10,15 @@ 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:19:1
--> $DIR/empty_line_after_outer_attribute.rs:23:1
|
LL | / #[crate_type = "lib"]
LL | |
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:24:1
--> $DIR/empty_line_after_outer_attribute.rs:28:1
|
LL | / #[crate_type = "lib"]
LL | |
@@ -27,23 +27,23 @@ 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:31:1
--> $DIR/empty_line_after_outer_attribute.rs:35:1
|
LL | / #[crate_type = "lib"]
LL | |
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:39:1
--> $DIR/empty_line_after_outer_attribute.rs:43:1
|
LL | / #[crate_type = "lib"]
LL | |
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:47:1
--> $DIR/empty_line_after_outer_attribute.rs:51:1
|
LL | / #[crate_type = "lib"]
LL | |