Skip to content

Commit e656531

Browse files
committed
submodules: update clippy from a8d90f6 to fd0428f
Changes: ```` Treat more strange pattern Split up `if_same_then_else` ui test Apply review comments Run `update_lints` Reduce span range Rename `ok_if_let` to `if_let_some_result` Apply review comments Add suggestion in `if_let_some_result` rustup rust-lang/rust#67712 Allow `unused_self` lint at the function level Downgrade range_plus_one to pedantic Rustup to rust-lang/rust#68204 Add lifetimes to `LateLintPass` Fix rustc lint import paths generated by `new_lint` Add lint for default lint description Update documentation for adding new lints Generate new lints easily Split up `booleans` ui test Fix the ordering on `nonminimal_bool` ````
1 parent e0b22d4 commit e656531

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1236
-673
lines changed

clippy_dev/src/main.rs

+52
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use clap::{App, Arg, SubCommand};
44
use clippy_dev::*;
55

66
mod fmt;
7+
mod new_lint;
78
mod stderr_length_check;
89

910
#[derive(PartialEq)]
@@ -51,6 +52,47 @@ fn main() {
5152
.help("Checks that util/dev update_lints has been run. Used on CI."),
5253
),
5354
)
55+
.subcommand(
56+
SubCommand::with_name("new_lint")
57+
.about("Create new lint and run util/dev update_lints")
58+
.arg(
59+
Arg::with_name("pass")
60+
.short("p")
61+
.long("pass")
62+
.help("Specify whether the lint runs during the early or late pass")
63+
.takes_value(true)
64+
.possible_values(&["early", "late"])
65+
.required(true),
66+
)
67+
.arg(
68+
Arg::with_name("name")
69+
.short("n")
70+
.long("name")
71+
.help("Name of the new lint in snake case, ex: fn_too_long")
72+
.takes_value(true)
73+
.required(true),
74+
)
75+
.arg(
76+
Arg::with_name("category")
77+
.short("c")
78+
.long("category")
79+
.help("What category the lint belongs to")
80+
.default_value("nursery")
81+
.possible_values(&[
82+
"style",
83+
"correctness",
84+
"complexity",
85+
"perf",
86+
"pedantic",
87+
"restriction",
88+
"cargo",
89+
"nursery",
90+
"internal",
91+
"internal_warn",
92+
])
93+
.takes_value(true),
94+
),
95+
)
5496
.arg(
5597
Arg::with_name("limit-stderr-length")
5698
.long("limit-stderr-length")
@@ -75,6 +117,16 @@ fn main() {
75117
update_lints(&UpdateMode::Change);
76118
}
77119
},
120+
("new_lint", Some(matches)) => {
121+
match new_lint::create(
122+
matches.value_of("pass"),
123+
matches.value_of("name"),
124+
matches.value_of("category"),
125+
) {
126+
Ok(_) => update_lints(&UpdateMode::Change),
127+
Err(e) => eprintln!("Unable to create lint: {}", e),
128+
}
129+
},
78130
_ => {},
79131
}
80132
}

clippy_dev/src/new_lint.rs

+185
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
use std::fs::{File, OpenOptions};
2+
use std::io;
3+
use std::io::prelude::*;
4+
use std::io::ErrorKind;
5+
use std::path::{Path, PathBuf};
6+
7+
pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> Result<(), io::Error> {
8+
let pass = pass.expect("`pass` argument is validated by clap");
9+
let lint_name = lint_name.expect("`name` argument is validated by clap");
10+
let category = category.expect("`category` argument is validated by clap");
11+
12+
match open_files(lint_name) {
13+
Ok((mut test_file, mut lint_file)) => {
14+
let (pass_type, pass_lifetimes, pass_import, context_import) = match pass {
15+
"early" => ("EarlyLintPass", "", "use syntax::ast::*;", "EarlyContext"),
16+
"late" => ("LateLintPass", "<'_, '_>", "use rustc_hir::*;", "LateContext"),
17+
_ => {
18+
unreachable!("`pass_type` should only ever be `early` or `late`!");
19+
},
20+
};
21+
22+
let camel_case_name = to_camel_case(lint_name);
23+
24+
if let Err(e) = test_file.write_all(get_test_file_contents(lint_name).as_bytes()) {
25+
return Err(io::Error::new(
26+
ErrorKind::Other,
27+
format!("Could not write to test file: {}", e),
28+
));
29+
};
30+
31+
if let Err(e) = lint_file.write_all(
32+
get_lint_file_contents(
33+
pass_type,
34+
pass_lifetimes,
35+
lint_name,
36+
&camel_case_name,
37+
category,
38+
pass_import,
39+
context_import,
40+
)
41+
.as_bytes(),
42+
) {
43+
return Err(io::Error::new(
44+
ErrorKind::Other,
45+
format!("Could not write to lint file: {}", e),
46+
));
47+
}
48+
Ok(())
49+
},
50+
Err(e) => Err(io::Error::new(
51+
ErrorKind::Other,
52+
format!("Unable to create lint: {}", e),
53+
)),
54+
}
55+
}
56+
57+
fn open_files(lint_name: &str) -> Result<(File, File), io::Error> {
58+
let project_root = project_root()?;
59+
60+
let test_file_path = project_root.join("tests").join("ui").join(format!("{}.rs", lint_name));
61+
let lint_file_path = project_root
62+
.join("clippy_lints")
63+
.join("src")
64+
.join(format!("{}.rs", lint_name));
65+
66+
if Path::new(&test_file_path).exists() {
67+
return Err(io::Error::new(
68+
ErrorKind::AlreadyExists,
69+
format!("test file {:?} already exists", test_file_path),
70+
));
71+
}
72+
if Path::new(&lint_file_path).exists() {
73+
return Err(io::Error::new(
74+
ErrorKind::AlreadyExists,
75+
format!("lint file {:?} already exists", lint_file_path),
76+
));
77+
}
78+
79+
let test_file = OpenOptions::new().write(true).create_new(true).open(test_file_path)?;
80+
let lint_file = OpenOptions::new().write(true).create_new(true).open(lint_file_path)?;
81+
82+
Ok((test_file, lint_file))
83+
}
84+
85+
fn project_root() -> Result<PathBuf, io::Error> {
86+
let current_dir = std::env::current_dir()?;
87+
for path in current_dir.ancestors() {
88+
let result = std::fs::read_to_string(path.join("Cargo.toml"));
89+
if let Err(err) = &result {
90+
if err.kind() == io::ErrorKind::NotFound {
91+
continue;
92+
}
93+
}
94+
95+
let content = result?;
96+
if content.contains("[package]\nname = \"clippy\"") {
97+
return Ok(path.to_path_buf());
98+
}
99+
}
100+
Err(io::Error::new(ErrorKind::Other, "Unable to find project root"))
101+
}
102+
103+
fn to_camel_case(name: &str) -> String {
104+
name.split('_')
105+
.map(|s| {
106+
if s.is_empty() {
107+
String::from("")
108+
} else {
109+
[&s[0..1].to_uppercase(), &s[1..]].concat()
110+
}
111+
})
112+
.collect()
113+
}
114+
115+
fn get_test_file_contents(lint_name: &str) -> String {
116+
format!(
117+
"#![warn(clippy::{})]
118+
119+
fn main() {{
120+
// test code goes here
121+
}}
122+
",
123+
lint_name
124+
)
125+
}
126+
127+
fn get_lint_file_contents(
128+
pass_type: &str,
129+
pass_lifetimes: &str,
130+
lint_name: &str,
131+
camel_case_name: &str,
132+
category: &str,
133+
pass_import: &str,
134+
context_import: &str,
135+
) -> String {
136+
format!(
137+
"use rustc_lint::{{LintArray, LintPass, {type}, {context_import}}};
138+
use rustc_session::{{declare_lint_pass, declare_tool_lint}};
139+
{pass_import}
140+
141+
declare_clippy_lint! {{
142+
/// **What it does:**
143+
///
144+
/// **Why is this bad?**
145+
///
146+
/// **Known problems:** None.
147+
///
148+
/// **Example:**
149+
///
150+
/// ```rust
151+
/// // example code
152+
/// ```
153+
pub {name_upper},
154+
{category},
155+
\"default lint description\"
156+
}}
157+
158+
declare_lint_pass!({name_camel} => [{name_upper}]);
159+
160+
impl {type}{lifetimes} for {name_camel} {{}}
161+
",
162+
type=pass_type,
163+
lifetimes=pass_lifetimes,
164+
name_upper=lint_name.to_uppercase(),
165+
name_camel=camel_case_name,
166+
category=category,
167+
pass_import=pass_import,
168+
context_import=context_import
169+
)
170+
}
171+
172+
#[test]
173+
fn test_camel_case() {
174+
let s = "a_lint";
175+
let s2 = to_camel_case(s);
176+
assert_eq!(s2, "ALint");
177+
178+
let name = "a_really_long_new_lint";
179+
let name2 = to_camel_case(name);
180+
assert_eq!(name2, "AReallyLongNewLint");
181+
182+
let name3 = "lint__name";
183+
let name4 = to_camel_case(name3);
184+
assert_eq!(name4, "LintName");
185+
}

clippy_lints/src/booleans.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
207207
}
208208
},
209209
Or(v) => {
210-
for (index, inner) in v.iter().enumerate() {
210+
for (index, inner) in v.iter().rev().enumerate() {
211211
if index > 0 {
212212
self.output.push_str(" || ");
213213
}

clippy_lints/src/copy_iterator.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ declare_lint_pass!(CopyIterator => [COPY_ITERATOR]);
3333

3434
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CopyIterator {
3535
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item<'_>) {
36-
if let ItemKind::Impl(_, _, _, _, Some(ref trait_ref), _, _) = item.kind {
36+
if let ItemKind::Impl {
37+
of_trait: Some(ref trait_ref),
38+
..
39+
} = item.kind
40+
{
3741
let ty = cx.tcx.type_of(cx.tcx.hir().local_def_id(item.hir_id));
3842

3943
if is_copy(cx, ty) && match_path(&trait_ref.path, &paths::ITERATOR) {

clippy_lints/src/derive.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ declare_lint_pass!(Derive => [EXPL_IMPL_CLONE_ON_COPY, DERIVE_HASH_XOR_EQ]);
6666

6767
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Derive {
6868
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item<'_>) {
69-
if let ItemKind::Impl(_, _, _, _, Some(ref trait_ref), _, _) = item.kind {
69+
if let ItemKind::Impl {
70+
of_trait: Some(ref trait_ref),
71+
..
72+
} = item.kind
73+
{
7074
let ty = cx.tcx.type_of(cx.tcx.hir().local_def_id(item.hir_id));
7175
let is_automatically_derived = is_automatically_derived(&*item.attrs);
7276

clippy_lints/src/doc.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DocMarkdown {
159159
lint_for_missing_headers(cx, item.hir_id, item.span, sig, headers);
160160
}
161161
},
162-
hir::ItemKind::Impl(_, _, _, _, ref trait_ref, ..) => {
162+
hir::ItemKind::Impl {
163+
of_trait: ref trait_ref,
164+
..
165+
} => {
163166
self.in_trait_impl = trait_ref.is_some();
164167
},
165168
_ => {},
166169
}
167170
}
168171

169172
fn check_item_post(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item<'_>) {
170-
if let hir::ItemKind::Impl(..) = item.kind {
173+
if let hir::ItemKind::Impl { .. } = item.kind {
171174
self.in_trait_impl = false;
172175
}
173176
}

clippy_lints/src/escape.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxedLocal {
6464
let parent_node = cx.tcx.hir().find(parent_id);
6565

6666
if let Some(Node::Item(item)) = parent_node {
67-
if let ItemKind::Impl(_, _, _, _, Some(..), _, _) = item.kind {
67+
if let ItemKind::Impl { of_trait: Some(_), .. } = item.kind {
6868
return;
6969
}
7070
}

clippy_lints/src/fallible_impl_from.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FallibleImplFrom {
3636
// check for `impl From<???> for ..`
3737
let impl_def_id = cx.tcx.hir().local_def_id(item.hir_id);
3838
if_chain! {
39-
if let hir::ItemKind::Impl(.., impl_items) = item.kind;
39+
if let hir::ItemKind::Impl{ items: impl_items, .. } = item.kind;
4040
if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(impl_def_id);
4141
if match_def_path(cx, impl_trait_ref.def_id, &FROM_TRAIT);
4242
then {

clippy_lints/src/functions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
196196
hir_id: hir::HirId,
197197
) {
198198
let is_impl = if let Some(hir::Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
199-
matches!(item.kind, hir::ItemKind::Impl(_, _, _, _, Some(_), _, _))
199+
matches!(item.kind, hir::ItemKind::Impl{ of_trait: Some(_), .. })
200200
} else {
201201
false
202202
};

clippy_lints/src/ok_if_let.rs renamed to clippy_lints/src/if_let_some_result.rs

+23-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use crate::utils::{match_type, method_chain_args, paths, snippet, span_help_and_lint};
1+
use crate::utils::{match_type, method_chain_args, paths, snippet_with_applicability, span_lint_and_sugg};
22
use if_chain::if_chain;
3+
use rustc_errors::Applicability;
34
use rustc_hir::*;
45
use rustc_lint::{LateContext, LateLintPass};
56
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -39,20 +40,32 @@ declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]);
3940
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet {
4041
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
4142
if_chain! { //begin checking variables
42-
if let ExprKind::Match(ref op, ref body, ref source) = expr.kind; //test if expr is a match
43-
if let MatchSource::IfLetDesugar { .. } = *source; //test if it is an If Let
44-
if let ExprKind::MethodCall(_, _, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok()
43+
if let ExprKind::Match(ref op, ref body, source) = expr.kind; //test if expr is a match
44+
if let MatchSource::IfLetDesugar { .. } = source; //test if it is an If Let
45+
if let ExprKind::MethodCall(_, ok_span, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok()
4546
if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation
4647
if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
48+
let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT);
49+
if print::to_string(print::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type;
4750

4851
then {
49-
let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT);
50-
let some_expr_string = snippet(cx, y[0].span, "");
51-
if print::to_string(print::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type {
52-
span_help_and_lint(cx, IF_LET_SOME_RESULT, expr.span,
52+
let mut applicability = Applicability::MachineApplicable;
53+
let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability);
54+
let trimmed_ok = snippet_with_applicability(cx, op.span.until(ok_span), "", &mut applicability);
55+
let sugg = format!(
56+
"if let Ok({}) = {}",
57+
some_expr_string,
58+
trimmed_ok.trim().trim_end_matches('.'),
59+
);
60+
span_lint_and_sugg(
61+
cx,
62+
IF_LET_SOME_RESULT,
63+
expr.span.with_hi(op.span.hi()),
5364
"Matching on `Some` with `ok()` is redundant",
54-
&format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string));
55-
}
65+
&format!("Consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
66+
sugg,
67+
applicability,
68+
);
5669
}
5770
}
5871
}

0 commit comments

Comments
 (0)