about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPhilipp Hansch <dev@phansch.net>2020-05-17 18:14:43 +0200
committerPhilipp Hansch <dev@phansch.net>2020-05-26 16:52:02 +0200
commit67167be1679c60eefa2c314c5e4a2b673d5eef11 (patch)
tree48a4ac82e3ab3c68ccd322847f216f9136b8db4a
parent578692d9b0205102968032bd4a63c3b262c43b63 (diff)
downloadrust-67167be1679c60eefa2c314c5e4a2b673d5eef11.tar.gz
rust-67167be1679c60eefa2c314c5e4a2b673d5eef11.zip
Make empty_line_after_outer_attr an early lint
-rw-r--r--clippy_lints/Cargo.toml4
-rw-r--r--clippy_lints/src/attrs.rs75
-rw-r--r--tests/compile-test.rs2
-rw-r--r--tests/ui/auxiliary/proc_macro_attr.rs37
-rw-r--r--tests/ui/empty_line_after_outer_attribute.rs19
-rw-r--r--tests/ui/empty_line_after_outer_attribute.stderr12
6 files changed, 109 insertions, 40 deletions
diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml
index 1c0be727834..043a79f2001 100644
--- a/clippy_lints/Cargo.toml
+++ b/clippy_lints/Cargo.toml
@@ -33,5 +33,9 @@ semver = "0.9.0"
 # see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864>
 url = { version =  "2.1.0", features = ["serde"] }
 
+[dev-dependencies]
+quote = "*"
+syn = { version = "*", features = ["full"] }
+
 [features]
 deny-warnings = []
diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs
index 64abc9fdc71..41f125d4839 100644
--- a/clippy_lints/src/attrs.rs
+++ b/clippy_lints/src/attrs.rs
@@ -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
diff --git a/tests/compile-test.rs b/tests/compile-test.rs
index a5de8429390..2758b9a7e76 100644
--- a/tests/compile-test.rs
+++ b/tests/compile-test.rs
@@ -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() {
diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs
new file mode 100644
index 00000000000..e6626d57a77
--- /dev/null
+++ b/tests/ui/auxiliary/proc_macro_attr.rs
@@ -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))
+}
diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs
index 5343dff9da1..3e92bca986a 100644
--- a/tests/ui/empty_line_after_outer_attribute.rs
+++ b/tests/ui/empty_line_after_outer_attribute.rs
@@ -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() {}
diff --git a/tests/ui/empty_line_after_outer_attribute.stderr b/tests/ui/empty_line_after_outer_attribute.stderr
index d8c9786541f..bf753a732f0 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:7:1
+  --> $DIR/empty_line_after_outer_attribute.rs:11: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:19:1
+  --> $DIR/empty_line_after_outer_attribute.rs:23: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:24:1
+  --> $DIR/empty_line_after_outer_attribute.rs:28: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:31:1
+  --> $DIR/empty_line_after_outer_attribute.rs:35: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:39:1
+  --> $DIR/empty_line_after_outer_attribute.rs:43: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:47:1
+  --> $DIR/empty_line_after_outer_attribute.rs:51:1
    |
 LL | / #[crate_type = "lib"]
 LL | |