Skip to content

Commit eed9baa

Browse files
committed
Merge pull request #698 from mcarton/conf
Add a configuration file and a POC `BLACKLISTED_NAME` lint
2 parents 34d57c5 + 14dcb60 commit eed9baa

25 files changed

+590
-56
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ plugin = true
2121
regex-syntax = "0.2.2"
2222
regex_macros = { version = "0.1.28", optional = true }
2323
semver = "0.2.1"
24+
toml = "0.1"
2425
unicode-normalization = "0.1"
2526

2627
[dev-dependencies]

README.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,23 @@
66

77
A collection of lints to catch common mistakes and improve your Rust code.
88

9-
[Jump to usage instructions](#usage)
10-
11-
[Jump to link with clippy-service](#link-with-clippy-service)
9+
Table of contents:
10+
* [Lint list](#lints)
11+
* [Usage instructions](#usage)
12+
* [Configuration](#configuration)
13+
* [*clippy-service*](#link-with-clippy-service)
14+
* [License](#license)
1215

1316
##Lints
14-
There are 134 lints included in this crate:
17+
There are 136 lints included in this crate:
1518

1619
name | default | meaning
1720
---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1821
[absurd_extreme_comparisons](https://github.com/Manishearth/rust-clippy/wiki#absurd_extreme_comparisons) | warn | a comparison involving a maximum or minimum value involves a case that is always true or always false
1922
[almost_swapped](https://github.com/Manishearth/rust-clippy/wiki#almost_swapped) | warn | `foo = bar; bar = foo` sequence
2023
[approx_constant](https://github.com/Manishearth/rust-clippy/wiki#approx_constant) | warn | the approximate of a known float constant (in `std::f64::consts` or `std::f32::consts`) is found; suggests to use the constant
2124
[bad_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#bad_bit_mask) | warn | expressions of the form `_ & mask == select` that will only ever return `true` or `false` (because in the example `select` containing bits that `mask` doesn't have)
25+
[blacklisted_name](https://github.com/Manishearth/rust-clippy/wiki#blacklisted_name) | warn | usage of a blacklisted/placeholder name
2226
[block_in_if_condition_expr](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_expr) | warn | braces can be eliminated in conditions that are expressions, e.g `if { true } ...`
2327
[block_in_if_condition_stmt](https://github.com/Manishearth/rust-clippy/wiki#block_in_if_condition_stmt) | warn | avoid complex blocks in conditions, instead move the block higher and bind it with 'let'; e.g: `if { let x = true; x } ...`
2428
[bool_comparison](https://github.com/Manishearth/rust-clippy/wiki#bool_comparison) | warn | comparing a variable to a boolean, e.g. `if x == true`
@@ -126,6 +130,7 @@ name
126130
[suspicious_assignment_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_assignment_formatting) | warn | suspicious formatting of `*=`, `-=` or `!=`
127131
[suspicious_else_formatting](https://github.com/Manishearth/rust-clippy/wiki#suspicious_else_formatting) | warn | suspicious formatting of `else if`
128132
[temporary_assignment](https://github.com/Manishearth/rust-clippy/wiki#temporary_assignment) | warn | assignments to temporaries
133+
[too_many_arguments](https://github.com/Manishearth/rust-clippy/wiki#too_many_arguments) | warn | functions with too many arguments
129134
[toplevel_ref_arg](https://github.com/Manishearth/rust-clippy/wiki#toplevel_ref_arg) | warn | An entire binding was declared as `ref`, in a function argument (`fn foo(ref x: Bar)`), or a `let` statement (`let ref x = foo()`). In such cases, it is preferred to take references with `&`.
130135
[trivial_regex](https://github.com/Manishearth/rust-clippy/wiki#trivial_regex) | warn | finds trivial regular expressions in `Regex::new(_)` invocations
131136
[type_complexity](https://github.com/Manishearth/rust-clippy/wiki#type_complexity) | warn | usage of very complex types; recommends factoring out parts into `type` definitions
@@ -230,6 +235,22 @@ And, in your `main.rs` or `lib.rs`:
230235
#![cfg_attr(feature="clippy", plugin(clippy))]
231236
```
232237

238+
## Configuration
239+
Some lints can be configured in a `clippy.toml` file. It contains basic `variable = value` mapping eg.
240+
241+
```toml
242+
blacklisted-names = ["toto", "tata", "titi"]
243+
cyclomatic-complexity-threshold = 30
244+
```
245+
246+
See the wiki for more information about which lints can be configured and the
247+
meaning of the variables.
248+
249+
You can also specify the path to the configuration file with:
250+
```rust
251+
#![plugin(clippy(conf_file="path/to/clippy's/configuration"))]
252+
```
253+
233254
##Link with clippy service
234255
`clippy-service` is a rust web initiative providing `rust-clippy` as a web service.
235256

src/blacklisted_name.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use rustc::lint::*;
2+
use rustc_front::hir::*;
3+
use utils::span_lint;
4+
5+
/// **What it does:** This lints about usage of blacklisted names.
6+
///
7+
/// **Why is this bad?** These names are usually placeholder names and should be avoided.
8+
///
9+
/// **Known problems:** None.
10+
///
11+
/// **Example:** `let foo = 3.14;`
12+
declare_lint! {
13+
pub BLACKLISTED_NAME,
14+
Warn,
15+
"usage of a blacklisted/placeholder name"
16+
}
17+
18+
#[derive(Clone, Debug)]
19+
pub struct BlackListedName {
20+
blacklist: Vec<String>,
21+
}
22+
23+
impl BlackListedName {
24+
pub fn new(blacklist: Vec<String>) -> BlackListedName {
25+
BlackListedName { blacklist: blacklist }
26+
}
27+
}
28+
29+
impl LintPass for BlackListedName {
30+
fn get_lints(&self) -> LintArray {
31+
lint_array!(BLACKLISTED_NAME)
32+
}
33+
}
34+
35+
impl LateLintPass for BlackListedName {
36+
fn check_pat(&mut self, cx: &LateContext, pat: &Pat) {
37+
if let PatKind::Ident(_, ref ident, _) = pat.node {
38+
if self.blacklist.iter().any(|s| s == &*ident.node.name.as_str()) {
39+
span_lint(cx,
40+
BLACKLISTED_NAME,
41+
pat.span,
42+
&format!("use of a blacklisted/placeholder name `{}`", ident.node.name));
43+
}
44+
}
45+
}
46+
}

src/functions.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
use rustc::lint::*;
2+
use rustc_front::hir;
3+
use rustc_front::intravisit;
4+
use syntax::ast;
5+
use syntax::codemap::Span;
6+
use utils::span_lint;
7+
8+
/// **What it does:** Check for functions with too many parameters.
9+
///
10+
/// **Why is this bad?** Functions with lots of parameters are considered bad style and reduce
11+
/// readability (“what does the 5th parameter means?”). Consider grouping some parameters into a
12+
/// new type.
13+
///
14+
/// **Known problems:** None.
15+
///
16+
/// **Example:**
17+
///
18+
/// ```
19+
/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) { .. }
20+
/// ```
21+
declare_lint! {
22+
pub TOO_MANY_ARGUMENTS,
23+
Warn,
24+
"functions with too many arguments"
25+
}
26+
27+
#[derive(Copy,Clone)]
28+
pub struct Functions {
29+
threshold: u64,
30+
}
31+
32+
impl Functions {
33+
pub fn new(threshold: u64) -> Functions {
34+
Functions {
35+
threshold: threshold
36+
}
37+
}
38+
}
39+
40+
impl LintPass for Functions {
41+
fn get_lints(&self) -> LintArray {
42+
lint_array!(TOO_MANY_ARGUMENTS)
43+
}
44+
}
45+
46+
impl LateLintPass for Functions {
47+
fn check_fn(&mut self, cx: &LateContext, _: intravisit::FnKind, decl: &hir::FnDecl, _: &hir::Block, span: Span, nodeid: ast::NodeId) {
48+
use rustc::front::map::Node::*;
49+
50+
if let Some(NodeItem(ref item)) = cx.tcx.map.find(cx.tcx.map.get_parent_node(nodeid)) {
51+
match item.node {
52+
hir::ItemImpl(_, _, _, Some(_), _, _) | hir::ItemDefaultImpl(..) => return,
53+
_ => (),
54+
}
55+
}
56+
57+
self.check_arg_number(cx, decl, span);
58+
}
59+
60+
fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
61+
if let hir::MethodTraitItem(ref sig, _) = item.node {
62+
self.check_arg_number(cx, &sig.decl, item.span);
63+
}
64+
}
65+
}
66+
67+
impl Functions {
68+
fn check_arg_number(&self, cx: &LateContext, decl: &hir::FnDecl, span: Span) {
69+
let args = decl.inputs.len() as u64;
70+
if args > self.threshold {
71+
span_lint(cx, TOO_MANY_ARGUMENTS, span,
72+
&format!("this function has to many arguments ({}/{})", args, self.threshold));
73+
}
74+
}
75+
}

src/lib.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![feature(type_macros)]
12
#![feature(plugin_registrar, box_syntax)]
23
#![feature(rustc_private, collections)]
34
#![feature(iter_arith)]
@@ -18,6 +19,8 @@ extern crate rustc;
1819
#[macro_use]
1920
extern crate rustc_front;
2021

22+
extern crate toml;
23+
2124
// Only for the compile time checking of paths
2225
extern crate core;
2326
extern crate collections;
@@ -44,6 +47,7 @@ pub mod approx_const;
4447
pub mod array_indexing;
4548
pub mod attrs;
4649
pub mod bit_mask;
50+
pub mod blacklisted_name;
4751
pub mod block_in_if_condition;
4852
pub mod collapsible_if;
4953
pub mod copies;
@@ -59,6 +63,7 @@ pub mod escape;
5963
pub mod eta_reduction;
6064
pub mod format;
6165
pub mod formatting;
66+
pub mod functions;
6267
pub mod identity_op;
6368
pub mod if_not_else;
6469
pub mod items_after_statements;
@@ -107,6 +112,33 @@ mod reexport {
107112
#[plugin_registrar]
108113
#[cfg_attr(rustfmt, rustfmt_skip)]
109114
pub fn plugin_registrar(reg: &mut Registry) {
115+
let conf = match utils::conf::conf_file(reg.args()) {
116+
Ok(file_name) => {
117+
// if the user specified a file, it must exist, otherwise default to `clippy.toml` but
118+
// do not require the file to exist
119+
let (ref file_name, must_exist) = if let Some(ref file_name) = file_name {
120+
(&**file_name, true)
121+
} else {
122+
("clippy.toml", false)
123+
};
124+
125+
let (conf, errors) = utils::conf::read_conf(&file_name, must_exist);
126+
127+
// all conf errors are non-fatal, we just use the default conf in case of error
128+
for error in errors {
129+
reg.sess.struct_err(&format!("error reading Clippy's configuration file: {}", error)).emit();
130+
}
131+
132+
conf
133+
}
134+
Err((err, span)) => {
135+
reg.sess.struct_span_err(span, err)
136+
.span_note(span, "Clippy will use defaulf configuration")
137+
.emit();
138+
utils::conf::Conf::default()
139+
}
140+
};
141+
110142
reg.register_late_lint_pass(box types::TypePass);
111143
reg.register_late_lint_pass(box misc::TopLevelRefPass);
112144
reg.register_late_lint_pass(box misc::CmpNan);
@@ -144,7 +176,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
144176
reg.register_late_lint_pass(box entry::HashMapLint);
145177
reg.register_late_lint_pass(box ranges::StepByZero);
146178
reg.register_late_lint_pass(box types::CastPass);
147-
reg.register_late_lint_pass(box types::TypeComplexityPass);
179+
reg.register_late_lint_pass(box types::TypeComplexityPass::new(conf.type_complexity_threshold));
148180
reg.register_late_lint_pass(box matches::MatchPass);
149181
reg.register_late_lint_pass(box misc::PatternPass);
150182
reg.register_late_lint_pass(box minmax::MinMaxPass);
@@ -157,7 +189,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
157189
reg.register_late_lint_pass(box map_clone::MapClonePass);
158190
reg.register_late_lint_pass(box temporary_assignment::TemporaryAssignmentPass);
159191
reg.register_late_lint_pass(box transmute::UselessTransmute);
160-
reg.register_late_lint_pass(box cyclomatic_complexity::CyclomaticComplexity::new(25));
192+
reg.register_late_lint_pass(box cyclomatic_complexity::CyclomaticComplexity::new(conf.cyclomatic_complexity_threshold));
161193
reg.register_late_lint_pass(box escape::EscapePass);
162194
reg.register_early_lint_pass(box misc_early::MiscEarly);
163195
reg.register_late_lint_pass(box misc::UsedUnderscoreBinding);
@@ -179,6 +211,8 @@ pub fn plugin_registrar(reg: &mut Registry) {
179211
reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional);
180212
reg.register_late_lint_pass(box unused_label::UnusedLabel);
181213
reg.register_late_lint_pass(box new_without_default::NewWithoutDefault);
214+
reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(conf.blacklisted_names));
215+
reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold));
182216

183217
reg.register_lint_group("clippy_pedantic", vec![
184218
array_indexing::INDEXING_SLICING,
@@ -211,6 +245,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
211245
attrs::INLINE_ALWAYS,
212246
bit_mask::BAD_BIT_MASK,
213247
bit_mask::INEFFECTIVE_BIT_MASK,
248+
blacklisted_name::BLACKLISTED_NAME,
214249
block_in_if_condition::BLOCK_IN_IF_CONDITION_EXPR,
215250
block_in_if_condition::BLOCK_IN_IF_CONDITION_STMT,
216251
collapsible_if::COLLAPSIBLE_IF,
@@ -230,6 +265,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
230265
format::USELESS_FORMAT,
231266
formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
232267
formatting::SUSPICIOUS_ELSE_FORMATTING,
268+
functions::TOO_MANY_ARGUMENTS,
233269
identity_op::IDENTITY_OP,
234270
if_not_else::IF_NOT_ELSE,
235271
items_after_statements::ITEMS_AFTER_STATEMENTS,

0 commit comments

Comments
 (0)