Skip to content

Commit b7a0b97

Browse files
authored
Merge pull request #2590 from phansch/fix_another_false_positive
Fix false positive in empty_line_after_outer_attr
2 parents b45801f + db1ec44 commit b7a0b97

File tree

4 files changed

+83
-3
lines changed

4 files changed

+83
-3
lines changed

clippy_lints/src/attrs.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc::ty::{self, TyCtxt};
77
use semver::Version;
88
use syntax::ast::{Attribute, AttrStyle, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
99
use syntax::codemap::Span;
10-
use utils::{in_macro, last_line_of_span, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_then};
10+
use utils::{in_macro, last_line_of_span, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_then, without_block_comments};
1111

1212
/// **What it does:** Checks for items annotated with `#[inline(always)]`,
1313
/// unless the annotated function is empty or simply panics.
@@ -85,7 +85,11 @@ declare_clippy_lint! {
8585
/// If it was meant to be an outer attribute, then the following item
8686
/// should not be separated by empty lines.
8787
///
88-
/// **Known problems:** None
88+
/// **Known problems:** Can cause false positives.
89+
///
90+
/// From the clippy side it's difficult to detect empty lines between an attributes and the
91+
/// following item because empty lines and comments are not part of the AST. The parsing
92+
/// currently works for basic cases but is not perfect.
8993
///
9094
/// **Example:**
9195
/// ```rust
@@ -105,7 +109,7 @@ declare_clippy_lint! {
105109
/// ```
106110
declare_clippy_lint! {
107111
pub EMPTY_LINE_AFTER_OUTER_ATTR,
108-
style,
112+
nursery,
109113
"empty line after outer attribute"
110114
}
111115

@@ -276,6 +280,8 @@ fn check_attrs(cx: &LateContext, span: Span, name: &Name, attrs: &[Attribute]) {
276280

277281
if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) {
278282
let lines = snippet.split('\n').collect::<Vec<_>>();
283+
let lines = without_block_comments(lines);
284+
279285
if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 {
280286
span_lint(
281287
cx,

clippy_lints/src/utils/mod.rs

+33
Original file line numberDiff line numberDiff line change
@@ -1086,3 +1086,36 @@ pub fn clip(tcx: TyCtxt, u: u128, ity: ast::UintTy) -> u128 {
10861086
let amt = 128 - bits;
10871087
(u << amt) >> amt
10881088
}
1089+
1090+
/// Remove block comments from the given Vec of lines
1091+
///
1092+
/// # Examples
1093+
///
1094+
/// ```rust,ignore
1095+
/// without_block_comments(vec!["/*", "foo", "*/"]);
1096+
/// // => vec![]
1097+
///
1098+
/// without_block_comments(vec!["bar", "/*", "foo", "*/"]);
1099+
/// // => vec!["bar"]
1100+
/// ```
1101+
pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> {
1102+
let mut without = vec![];
1103+
1104+
let mut nest_level = 0;
1105+
1106+
for line in lines.into_iter() {
1107+
if line.contains("/*") {
1108+
nest_level += 1;
1109+
continue;
1110+
} else if line.contains("*/") {
1111+
nest_level -= 1;
1112+
continue;
1113+
}
1114+
1115+
if nest_level == 0 {
1116+
without.push(line);
1117+
}
1118+
}
1119+
1120+
without
1121+
}

tests/ui/empty_line_after_outer_attribute.rs

+12
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,16 @@ pub enum FooFighter {
7979
Bar4
8080
}
8181

82+
// This should not produce a warning because the empty line is inside a block comment
83+
#[crate_type = "lib"]
84+
/*
85+
86+
*/
87+
pub struct S;
88+
89+
// This should not produce a warning
90+
#[crate_type = "lib"]
91+
/* test */
92+
pub struct T;
93+
8294
fn main() { }

tests/without_block_comments.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
extern crate clippy_lints;
2+
use clippy_lints::utils::without_block_comments;
3+
4+
#[test]
5+
fn test_lines_without_block_comments() {
6+
let result = without_block_comments(vec!["/*", "", "*/"]);
7+
println!("result: {:?}", result);
8+
assert!(result.is_empty());
9+
10+
let result = without_block_comments(
11+
vec!["", "/*", "", "*/", "#[crate_type = \"lib\"]", "/*", "", "*/", ""]
12+
);
13+
assert_eq!(result, vec!["", "#[crate_type = \"lib\"]", ""]);
14+
15+
let result = without_block_comments(vec!["/* rust", "", "*/"]);
16+
assert!(result.is_empty());
17+
18+
let result = without_block_comments(vec!["/* one-line comment */"]);
19+
assert!(result.is_empty());
20+
21+
let result = without_block_comments(vec!["/* nested", "/* multi-line", "comment", "*/", "test", "*/"]);
22+
assert!(result.is_empty());
23+
24+
let result = without_block_comments(vec!["/* nested /* inline /* comment */ test */ */"]);
25+
assert!(result.is_empty());
26+
27+
let result = without_block_comments(vec!["foo", "bar", "baz"]);
28+
assert_eq!(result, vec!["foo", "bar", "baz"]);
29+
}

0 commit comments

Comments
 (0)