Skip to content

Commit 0fbcb30

Browse files
author
Michael Wright
committed
Merge branch 'master' into dogfood_target_dir
2 parents fcabbeb + 83e2109 commit 0fbcb30

File tree

6 files changed

+133
-60
lines changed

6 files changed

+133
-60
lines changed

CONTRIBUTING.md

+23-24
Original file line numberDiff line numberDiff line change
@@ -15,41 +15,41 @@ High level approach:
1515

1616
All issues on Clippy are mentored, if you want help with a bug just ask @Manishearth, @llogiq, @mcarton or @oli-obk.
1717

18-
Some issues are easier than others. The [good first issue](https://github.com/rust-lang-nursery/rust-clippy/labels/good%20first%20issue)
18+
Some issues are easier than others. The [`good first issue`](https://github.com/rust-lang-nursery/rust-clippy/labels/good%20first%20issue)
1919
label can be used to find the easy issues. If you want to work on an issue, please leave a comment
2020
so that we can assign it to you!
2121

22-
Issues marked [T-AST](https://github.com/rust-lang-nursery/rust-clippy/labels/T-AST) involve simple
22+
Issues marked [`T-AST`](https://github.com/rust-lang-nursery/rust-clippy/labels/T-AST) involve simple
2323
matching of the syntax tree structure, and are generally easier than
24-
[T-middle](https://github.com/rust-lang-nursery/rust-clippy/labels/T-middle) issues, which involve types
24+
[`T-middle`](https://github.com/rust-lang-nursery/rust-clippy/labels/T-middle) issues, which involve types
2525
and resolved paths.
2626

27-
Issues marked [E-medium](https://github.com/rust-lang-nursery/rust-clippy/labels/E-medium) are generally
28-
pretty easy too, though it's recommended you work on an E-easy issue first. They are mostly classified
29-
as `E-medium`, since they might be somewhat involved code wise, but not difficult per-se.
30-
31-
[Llogiq's blog post on lints](https://llogiq.github.io/2015/06/04/workflows.html) is a nice primer
32-
to lint-writing, though it does get into advanced stuff. Most lints consist of an implementation of
33-
`LintPass` with one or more of its default methods overridden. See the existing lints for examples
34-
of this.
35-
36-
T-AST issues will generally need you to match against a predefined syntax structure. To figure out
27+
[`T-AST`](https://github.com/rust-lang-nursery/rust-clippy/labels/T-AST) issues will generally need you to match against a predefined syntax structure. To figure out
3728
how this syntax structure is encoded in the AST, it is recommended to run `rustc -Z ast-json` on an
3829
example of the structure and compare with the
3930
[nodes in the AST docs](http://manishearth.github.io/rust-internals-docs/syntax/ast/). Usually
4031
the lint will end up to be a nested series of matches and ifs,
4132
[like so](https://github.com/rust-lang-nursery/rust-clippy/blob/de5ccdfab68a5e37689f3c950ed1532ba9d652a0/src/misc.rs#L34).
4233

43-
T-middle issues can be more involved and require verifying types. The
34+
[`E-medium`](https://github.com/rust-lang-nursery/rust-clippy/labels/E-medium) issues are generally
35+
pretty easy too, though it's recommended you work on an E-easy issue first. They are mostly classified
36+
as `E-medium`, since they might be somewhat involved code wise, but not difficult per-se.
37+
38+
[`T-middle`](https://github.com/rust-lang-nursery/rust-clippy/labels/T-middle) issues can
39+
be more involved and require verifying types. The
4440
[`ty`](http://manishearth.github.io/rust-internals-docs/rustc/ty) module contains a
4541
lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of
4642
an AST expression). `match_def_path()` in Clippy's `utils` module can also be useful.
4743

4844
### Writing code
4945

50-
Compiling clippy can take almost a minute or more depending on your machine.
51-
You can set the environment flag `CARGO_INCREMENTAL=1` to cut down that time to
52-
almost a third on average, depending on the influence your change has.
46+
Compiling clippy from scratch can take almost a minute or more depending on your machine.
47+
However, since Rust 1.24.0 incremental compilation is enabled by default and compile times for small changes should be quick.
48+
49+
[Llogiq's blog post on lints](https://llogiq.github.io/2015/06/04/workflows.html) is a nice primer
50+
to lint-writing, though it does get into advanced stuff. Most lints consist of an implementation of
51+
`LintPass` with one or more of its default methods overridden. See the existing lints for examples
52+
of this.
5353

5454
Please document your lint with a doc comment akin to the following:
5555

@@ -61,8 +61,13 @@ Please document your lint with a doc comment akin to the following:
6161
/// **Known problems:** None. (Or describe where it could go wrong.)
6262
///
6363
/// **Example:**
64+
///
6465
/// ```rust
65-
/// Insert a short example if you have one.
66+
/// // Bad
67+
/// Insert a short example of code that triggers the lint
68+
///
69+
/// // Good
70+
/// Insert a short example of improved code that doesn't trigger the lint
6671
/// ```
6772
```
6873

@@ -80,12 +85,6 @@ If you don't want to wait for all tests to finish, you can also execute a single
8085
TESTNAME=ui/empty_line_after_outer_attr cargo test --test compile-test
8186
```
8287

83-
And you can also combine this with `CARGO_INCREMENTAL`:
84-
85-
```bash
86-
CARGO_INCREMENTAL=1 TESTNAME=ui/doc cargo test --test compile-test
87-
```
88-
8988
### Testing manually
9089

9190
Manually testing against an example file is useful if you have added some

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+
}

util/lintlib.py

+27-33
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@
77
import logging as log
88
log.basicConfig(level=log.INFO, format='%(levelname)s: %(message)s')
99

10-
Lint = collections.namedtuple('Lint', 'name level doc sourcefile')
10+
Lint = collections.namedtuple('Lint', 'name level doc sourcefile group')
1111
Config = collections.namedtuple('Config', 'name ty doc default')
1212

1313
lintname_re = re.compile(r'''pub\s+([A-Z_][A-Z_0-9]*)''')
14-
level_re = re.compile(r'''(Forbid|Deny|Warn|Allow)''')
15-
group_re = re.compile(r'''([a-z_][a-z_0-9]+)''')
14+
group_re = re.compile(r'''\s*([a-z_][a-z_0-9]+)''')
1615
conf_re = re.compile(r'''define_Conf! {\n([^}]*)\n}''', re.MULTILINE)
1716
confvar_re = re.compile(
1817
r'''/// Lint: (\w+). (.*).*\n\s*\([^,]+,\s+"([^"]+)",\s+([^=\)]+)=>\s+(.*)\),''', re.MULTILINE)
@@ -27,6 +26,7 @@
2726
"nursery": 'Allow',
2827
}
2928

29+
3030
def parse_lints(lints, filepath):
3131
last_comment = []
3232
comment = True
@@ -57,36 +57,30 @@ def parse_lints(lints, filepath):
5757
else:
5858
last_comment = []
5959
if not comment:
60-
if name:
61-
g = group_re.search(line)
62-
if g:
63-
group = g.group(1).lower()
64-
level = lint_levels[group]
65-
log.info("found %s with level %s in %s",
66-
name, level, filepath)
67-
lints.append(Lint(name, level, last_comment, filepath, group))
68-
last_comment = []
69-
comment = True
70-
else:
71-
m = lintname_re.search(line)
72-
if m:
73-
name = m.group(1).lower()
74-
75-
if deprecated:
76-
level = "Deprecated"
77-
else:
78-
while True:
79-
m = level_re.search(line)
80-
if m:
81-
level = m.group(0)
82-
break
83-
line = next(fp)
84-
if not clippy:
85-
log.info("found %s with level %s in %s",
86-
name, level, filepath)
87-
lints.append(Lint(name, level, last_comment, filepath, "deprecated"))
88-
last_comment = []
89-
comment = True
60+
m = lintname_re.search(line)
61+
62+
if m:
63+
name = m.group(1).lower()
64+
line = next(fp)
65+
66+
if deprecated:
67+
level = "Deprecated"
68+
group = "deprecated"
69+
else:
70+
while True:
71+
g = group_re.search(line)
72+
if g:
73+
group = g.group(1).lower()
74+
level = lint_levels[group]
75+
break
76+
line = next(fp)
77+
78+
log.info("found %s with level %s in %s",
79+
name, level, filepath)
80+
lints.append(Lint(name, level, last_comment, filepath, group))
81+
last_comment = []
82+
comment = True
83+
9084
if "}" in line:
9185
log.warn("Warning: missing Lint-Name in %s", filepath)
9286
comment = True

0 commit comments

Comments
 (0)