Merge pull request #3465 from flip1995/rustfmt

rustfmt everything once and for all
This commit is contained in:
Oliver S̶c̶h̶n̶e̶i̶d̶e̶r Scherer 2018-11-28 16:19:55 +01:00 committed by GitHub
commit f5831523d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
150 changed files with 3210 additions and 2882 deletions

View file

@ -30,6 +30,7 @@ before_install:
install: install:
- | - |
if [ -z ${INTEGRATION} ]; then if [ -z ${INTEGRATION} ]; then
rustup component add rustfmt-preview || cargo install --git https://github.com/rust-lang/rustfmt/ --force
if [ "$TRAVIS_OS_NAME" == "linux" ]; then if [ "$TRAVIS_OS_NAME" == "linux" ]; then
. $HOME/.nvm/nvm.sh . $HOME/.nvm/nvm.sh
nvm install stable nvm install stable

View file

@ -17,7 +17,9 @@ All contributors are expected to follow the [Rust Code of Conduct](http://www.ru
* [Author lint](#author-lint) * [Author lint](#author-lint)
* [Documentation](#documentation) * [Documentation](#documentation)
* [Running test suite](#running-test-suite) * [Running test suite](#running-test-suite)
* [Running rustfmt](#running-rustfmt)
* [Testing manually](#testing-manually) * [Testing manually](#testing-manually)
* [Linting Clippy with your local changes](#linting-clippy-with-your-local-changes)
* [How Clippy works](#how-clippy-works) * [How Clippy works](#how-clippy-works)
* [Fixing nightly build failures](#fixing-build-failures-caused-by-rust) * [Fixing nightly build failures](#fixing-build-failures-caused-by-rust)
* [Contributions](#contributions) * [Contributions](#contributions)
@ -146,6 +148,18 @@ Therefore you should use `tests/ui/update-all-references.sh` (after running
`cargo test`) and check whether the output looks as you expect with `git diff`. Commit all `cargo test`) and check whether the output looks as you expect with `git diff`. Commit all
`*.stderr` files, too. `*.stderr` files, too.
### Running rustfmt
[Rustfmt](https://github.com/rust-lang/rustfmt) is a tool for formatting Rust code according
to style guidelines. The code has to be formatted by `rustfmt` before a PR will be merged.
It can be installed via `rustup`:
```bash
rustup component add rustfmt-preview
```
Use `cargo fmt --all` to format the whole codebase.
### Testing manually ### Testing manually
Manually testing against an example file is useful if you have added some Manually testing against an example file is useful if you have added some
@ -153,7 +167,7 @@ Manually testing against an example file is useful if you have added some
local modifications, run `env CLIPPY_TESTS=true cargo run --bin clippy-driver -- -L ./target/debug input.rs` local modifications, run `env CLIPPY_TESTS=true cargo run --bin clippy-driver -- -L ./target/debug input.rs`
from the working copy root. from the working copy root.
### Linting Clippy with your changes locally ### Linting Clippy with your local changes
Clippy CI only passes if all lints defined in the version of the Clippy being Clippy CI only passes if all lints defined in the version of the Clippy being
tested pass (that is, dont report any suggestions). You can avoid prolonging tested pass (that is, dont report any suggestions). You can avoid prolonging
@ -246,7 +260,8 @@ Contributions to Clippy should be made in the form of GitHub pull requests. Each
be reviewed by a core contributor (someone with permission to land patches) and either landed in the be reviewed by a core contributor (someone with permission to land patches) and either landed in the
main tree or given feedback for changes that would be required. main tree or given feedback for changes that would be required.
All code in this repository is under the [Mozilla Public License, 2.0](https://www.mozilla.org/MPL/2.0/) All code in this repository is under the [Apache-2.0](http://www.apache.org/licenses/LICENSE-2.0>)
or the [MIT](http://opensource.org/licenses/MIT) license.
<!-- adapted from https://github.com/servo/servo/blob/master/CONTRIBUTING.md --> <!-- adapted from https://github.com/servo/servo/blob/master/CONTRIBUTING.md -->

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
fn main() { fn main() {
// Forward the profile to the main compilation // Forward the profile to the main compilation
println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap()); println!("cargo:rustc-env=PROFILE={}", std::env::var("PROFILE").unwrap());

View file

@ -26,6 +26,7 @@ cd clippy_dev && cargo test && cd ..
# Perform various checks for lint registration # Perform various checks for lint registration
./util/dev update_lints --check ./util/dev update_lints --check
cargo +nightly fmt --all -- --check
CLIPPY="`pwd`/target/debug/cargo-clippy clippy" CLIPPY="`pwd`/target/debug/cargo-clippy clippy"
# run clippy on its own codebase... # run clippy on its own codebase...

View file

@ -7,30 +7,35 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#![allow(clippy::default_hash_types)] #![allow(clippy::default_hash_types)]
use itertools::Itertools; use itertools::Itertools;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex; use regex::Regex;
use walkdir::WalkDir;
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::fs; use std::fs;
use std::io::prelude::*; use std::io::prelude::*;
use walkdir::WalkDir;
lazy_static! { lazy_static! {
static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(r#"(?x) static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(
r#"(?x)
declare_clippy_lint!\s*[\{(]\s* declare_clippy_lint!\s*[\{(]\s*
pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s* pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
(?P<cat>[a-z_]+)\s*,\s* (?P<cat>[a-z_]+)\s*,\s*
"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
"#).unwrap(); "#
static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new(r#"(?x) )
.unwrap();
static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new(
r#"(?x)
declare_deprecated_lint!\s*[{(]\s* declare_deprecated_lint!\s*[{(]\s*
pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s* pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})] "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
"#).unwrap(); "#
)
.unwrap();
static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap(); static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap();
pub static ref DOCS_LINK: String = "https://rust-lang.github.io/rust-clippy/master/index.html".to_string(); pub static ref DOCS_LINK: String = "https://rust-lang.github.io/rust-clippy/master/index.html".to_string();
} }
@ -57,13 +62,16 @@ impl Lint {
} }
/// Returns all non-deprecated lints and non-internal lints /// Returns all non-deprecated lints and non-internal lints
pub fn usable_lints(lints: impl Iterator<Item=Self>) -> impl Iterator<Item=Self> { pub fn usable_lints(lints: impl Iterator<Item = Self>) -> impl Iterator<Item = Self> {
lints.filter(|l| l.deprecation.is_none() && !l.is_internal()) lints.filter(|l| l.deprecation.is_none() && !l.is_internal())
} }
/// Returns the lints in a HashMap, grouped by the different lint groups /// Returns the lints in a HashMap, grouped by the different lint groups
pub fn by_lint_group(lints: &[Self]) -> HashMap<String, Vec<Self>> { pub fn by_lint_group(lints: &[Self]) -> HashMap<String, Vec<Self>> {
lints.iter().map(|lint| (lint.group.to_string(), lint.clone())).into_group_map() lints
.iter()
.map(|lint| (lint.group.to_string(), lint.clone()))
.into_group_map()
} }
pub fn is_internal(&self) -> bool { pub fn is_internal(&self) -> bool {
@ -73,7 +81,8 @@ impl Lint {
/// Generates the Vec items for `register_lint_group` calls in `clippy_lints/src/lib.rs`. /// Generates the Vec items for `register_lint_group` calls in `clippy_lints/src/lib.rs`.
pub fn gen_lint_group_list(lints: Vec<Lint>) -> Vec<String> { pub fn gen_lint_group_list(lints: Vec<Lint>) -> Vec<String> {
lints.into_iter() lints
.into_iter()
.filter_map(|l| { .filter_map(|l| {
if l.is_internal() || l.deprecation.is_some() { if l.is_internal() || l.deprecation.is_some() {
None None
@ -86,14 +95,17 @@ pub fn gen_lint_group_list(lints: Vec<Lint>) -> Vec<String> {
/// Generates the `pub mod module_name` list in `clippy_lints/src/lib.rs`. /// Generates the `pub mod module_name` list in `clippy_lints/src/lib.rs`.
pub fn gen_modules_list(lints: Vec<Lint>) -> Vec<String> { pub fn gen_modules_list(lints: Vec<Lint>) -> Vec<String> {
lints.into_iter() lints
.into_iter()
.filter_map(|l| { .filter_map(|l| {
if l.is_internal() || l.deprecation.is_some() { None } else { Some(l.module) } if l.is_internal() || l.deprecation.is_some() {
None
} else {
Some(l.module)
}
}) })
.unique() .unique()
.map(|module| { .map(|module| format!("pub mod {};", module))
format!("pub mod {};", module)
})
.sorted() .sorted()
} }
@ -109,35 +121,31 @@ pub fn gen_changelog_lint_list(lints: Vec<Lint>) -> Vec<String> {
} else { } else {
Some(format!("[`{}`]: {}#{}", l.name, DOCS_LINK.clone(), l.name)) Some(format!("[`{}`]: {}#{}", l.name, DOCS_LINK.clone(), l.name))
} }
}).collect() })
.collect()
} }
/// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`. /// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`.
pub fn gen_deprecated(lints: &[Lint]) -> Vec<String> { pub fn gen_deprecated(lints: &[Lint]) -> Vec<String> {
itertools::flatten( itertools::flatten(lints.iter().filter_map(|l| {
lints
.iter()
.filter_map(|l| {
l.clone().deprecation.and_then(|depr_text| { l.clone().deprecation.and_then(|depr_text| {
Some( Some(vec![
vec![
" store.register_removed(".to_string(), " store.register_removed(".to_string(),
format!(" \"{}\",", l.name), format!(" \"{}\",", l.name),
format!(" \"{}\",", depr_text), format!(" \"{}\",", depr_text),
" );".to_string() " );".to_string(),
] ])
)
}) })
}) }))
).collect() .collect()
} }
/// Gathers all files in `src/clippy_lints` and gathers all lints inside /// Gathers all files in `src/clippy_lints` and gathers all lints inside
pub fn gather_all() -> impl Iterator<Item=Lint> { pub fn gather_all() -> impl Iterator<Item = Lint> {
lint_files().flat_map(|f| gather_from_file(&f)) lint_files().flat_map(|f| gather_from_file(&f))
} }
fn gather_from_file(dir_entry: &walkdir::DirEntry) -> impl Iterator<Item=Lint> { fn gather_from_file(dir_entry: &walkdir::DirEntry) -> impl Iterator<Item = Lint> {
let mut file = fs::File::open(dir_entry.path()).unwrap(); let mut file = fs::File::open(dir_entry.path()).unwrap();
let mut content = String::new(); let mut content = String::new();
file.read_to_string(&mut content).unwrap(); file.read_to_string(&mut content).unwrap();
@ -145,24 +153,31 @@ fn gather_from_file(dir_entry: &walkdir::DirEntry) -> impl Iterator<Item=Lint> {
// If the lints are stored in mod.rs, we get the module name from // If the lints are stored in mod.rs, we get the module name from
// the containing directory: // the containing directory:
if filename == "mod" { if filename == "mod" {
filename = dir_entry.path().parent().unwrap().file_stem().unwrap().to_str().unwrap() filename = dir_entry
.path()
.parent()
.unwrap()
.file_stem()
.unwrap()
.to_str()
.unwrap()
} }
parse_contents(&content, filename) parse_contents(&content, filename)
} }
fn parse_contents(content: &str, filename: &str) -> impl Iterator<Item=Lint> { fn parse_contents(content: &str, filename: &str) -> impl Iterator<Item = Lint> {
let lints = DEC_CLIPPY_LINT_RE let lints = DEC_CLIPPY_LINT_RE
.captures_iter(content) .captures_iter(content)
.map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, filename)); .map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, filename));
let deprecated = DEC_DEPRECATED_LINT_RE let deprecated = DEC_DEPRECATED_LINT_RE
.captures_iter(content) .captures_iter(content)
.map(|m| Lint::new( &m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), filename)); .map(|m| Lint::new(&m["name"], "Deprecated", &m["desc"], Some(&m["desc"]), filename));
// Removing the `.collect::<Vec<Lint>>().into_iter()` causes some lifetime issues due to the map // Removing the `.collect::<Vec<Lint>>().into_iter()` causes some lifetime issues due to the map
lints.chain(deprecated).collect::<Vec<Lint>>().into_iter() lints.chain(deprecated).collect::<Vec<Lint>>().into_iter()
} }
/// Collects all .rs files in the `clippy_lints/src` directory /// Collects all .rs files in the `clippy_lints/src` directory
fn lint_files() -> impl Iterator<Item=walkdir::DirEntry> { fn lint_files() -> impl Iterator<Item = walkdir::DirEntry> {
// We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories. // We use `WalkDir` instead of `fs::read_dir` here in order to recurse into subdirectories.
// Otherwise we would not collect all the lints, for example in `clippy_lints/src/methods/`. // Otherwise we would not collect all the lints, for example in `clippy_lints/src/methods/`.
WalkDir::new("../clippy_lints/src") WalkDir::new("../clippy_lints/src")
@ -184,15 +199,27 @@ pub struct FileChange {
/// ///
/// See `replace_region_in_text` for documentation of the other options. /// See `replace_region_in_text` for documentation of the other options.
#[allow(clippy::expect_fun_call)] #[allow(clippy::expect_fun_call)]
pub fn replace_region_in_file<F>(path: &str, start: &str, end: &str, replace_start: bool, write_back: bool, replacements: F) -> FileChange where F: Fn() -> Vec<String> { pub fn replace_region_in_file<F>(
path: &str,
start: &str,
end: &str,
replace_start: bool,
write_back: bool,
replacements: F,
) -> FileChange
where
F: Fn() -> Vec<String>,
{
let mut f = fs::File::open(path).expect(&format!("File not found: {}", path)); let mut f = fs::File::open(path).expect(&format!("File not found: {}", path));
let mut contents = String::new(); let mut contents = String::new();
f.read_to_string(&mut contents).expect("Something went wrong reading the file"); f.read_to_string(&mut contents)
.expect("Something went wrong reading the file");
let file_change = replace_region_in_text(&contents, start, end, replace_start, replacements); let file_change = replace_region_in_text(&contents, start, end, replace_start, replacements);
if write_back { if write_back {
let mut f = fs::File::create(path).expect(&format!("File not found: {}", path)); let mut f = fs::File::create(path).expect(&format!("File not found: {}", path));
f.write_all(file_change.new_lines.as_bytes()).expect("Unable to write file"); f.write_all(file_change.new_lines.as_bytes())
.expect("Unable to write file");
// Ensure we write the changes with a trailing newline so that // Ensure we write the changes with a trailing newline so that
// the file has the proper line endings. // the file has the proper line endings.
f.write_all(b"\n").expect("Unable to write file"); f.write_all(b"\n").expect("Unable to write file");
@ -205,10 +232,10 @@ pub fn replace_region_in_file<F>(path: &str, start: &str, end: &str, replace_sta
/// * `text` is the input text on which you want to perform the replacement /// * `text` is the input text on which you want to perform the replacement
/// * `start` is a `&str` that describes the delimiter line before the region you want to replace. /// * `start` is a `&str` that describes the delimiter line before the region you want to replace.
/// As the `&str` will be converted to a `Regex`, this can contain regex syntax, too. /// As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
/// * `end` is a `&str` that describes the delimiter line until where the replacement should /// * `end` is a `&str` that describes the delimiter line until where the replacement should happen.
/// happen. As the `&str` will be converted to a `Regex`, this can contain regex syntax, too. /// As the `&str` will be converted to a `Regex`, this can contain regex syntax, too.
/// * If `replace_start` is true, the `start` delimiter line is replaced as well. /// * If `replace_start` is true, the `start` delimiter line is replaced as well. The `end`
/// The `end` delimiter line is never replaced. /// delimiter line is never replaced.
/// * `replacements` is a closure that has to return a `Vec<String>` which contains the new text. /// * `replacements` is a closure that has to return a `Vec<String>` which contains the new text.
/// ///
/// If you want to perform the replacement on files instead of already parsed text, /// If you want to perform the replacement on files instead of already parsed text,
@ -218,18 +245,16 @@ pub fn replace_region_in_file<F>(path: &str, start: &str, end: &str, replace_sta
/// ///
/// ``` /// ```
/// let the_text = "replace_start\nsome text\nthat will be replaced\nreplace_end"; /// let the_text = "replace_start\nsome text\nthat will be replaced\nreplace_end";
/// let result = clippy_dev::replace_region_in_text( /// let result = clippy_dev::replace_region_in_text(the_text, r#"replace_start"#, r#"replace_end"#, false, || {
/// the_text,
/// r#"replace_start"#,
/// r#"replace_end"#,
/// false,
/// || {
/// vec!["a different".to_string(), "text".to_string()] /// vec!["a different".to_string(), "text".to_string()]
/// } /// })
/// ).new_lines; /// .new_lines;
/// assert_eq!("replace_start\na different\ntext\nreplace_end", result); /// assert_eq!("replace_start\na different\ntext\nreplace_end", result);
/// ``` /// ```
pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> FileChange where F: Fn() -> Vec<String> { pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_start: bool, replacements: F) -> FileChange
where
F: Fn() -> Vec<String>,
{
let lines = text.lines(); let lines = text.lines();
let mut in_old_region = false; let mut in_old_region = false;
let mut found = false; let mut found = false;
@ -264,7 +289,7 @@ pub fn replace_region_in_text<F>(text: &str, start: &str, end: &str, replace_sta
FileChange { FileChange {
changed: lines.ne(new_lines.clone()), changed: lines.ne(new_lines.clone()),
new_lines: new_lines.join("\n") new_lines: new_lines.join("\n"),
} }
} }
@ -291,7 +316,9 @@ declare_deprecated_lint! {
"`assert!()` will be more flexible with RFC 2011" "`assert!()` will be more flexible with RFC 2011"
} }
"#, "#,
"module_name").collect(); "module_name",
)
.collect();
let expected = vec![ let expected = vec![
Lint::new("ptr_arg", "style", "really long text", None, "module_name"), Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
@ -301,7 +328,7 @@ declare_deprecated_lint! {
"Deprecated", "Deprecated",
"`assert!()` will be more flexible with RFC 2011", "`assert!()` will be more flexible with RFC 2011",
Some("`assert!()` will be more flexible with RFC 2011"), Some("`assert!()` will be more flexible with RFC 2011"),
"module_name" "module_name",
), ),
]; ];
assert_eq!(expected, result); assert_eq!(expected, result);
@ -312,7 +339,7 @@ fn test_replace_region() {
let text = "\nabc\n123\n789\ndef\nghi"; let text = "\nabc\n123\n789\ndef\nghi";
let expected = FileChange { let expected = FileChange {
changed: true, changed: true,
new_lines: "\nabc\nhello world\ndef\nghi".to_string() new_lines: "\nabc\nhello world\ndef\nghi".to_string(),
}; };
let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, false, || { let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, false, || {
vec!["hello world".to_string()] vec!["hello world".to_string()]
@ -325,7 +352,7 @@ fn test_replace_region_with_start() {
let text = "\nabc\n123\n789\ndef\nghi"; let text = "\nabc\n123\n789\ndef\nghi";
let expected = FileChange { let expected = FileChange {
changed: true, changed: true,
new_lines: "\nhello world\ndef\nghi".to_string() new_lines: "\nhello world\ndef\nghi".to_string(),
}; };
let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, true, || { let result = replace_region_in_text(text, r#"^\s*abc$"#, r#"^\s*def"#, true, || {
vec!["hello world".to_string()] vec!["hello world".to_string()]
@ -338,11 +365,9 @@ fn test_replace_region_no_changes() {
let text = "123\n456\n789"; let text = "123\n456\n789";
let expected = FileChange { let expected = FileChange {
changed: false, changed: false,
new_lines: "123\n456\n789".to_string() new_lines: "123\n456\n789".to_string(),
}; };
let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, || { let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, || vec![]);
vec![]
});
assert_eq!(expected, result); assert_eq!(expected, result);
} }
@ -352,11 +377,15 @@ fn test_usable_lints() {
Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"), Lint::new("should_assert_eq", "Deprecated", "abc", Some("Reason"), "module_name"),
Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name"), Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name"),
Lint::new("should_assert_eq2", "internal", "abc", None, "module_name"), Lint::new("should_assert_eq2", "internal", "abc", None, "module_name"),
Lint::new("should_assert_eq2", "internal_style", "abc", None, "module_name") Lint::new("should_assert_eq2", "internal_style", "abc", None, "module_name"),
];
let expected = vec![
Lint::new("should_assert_eq2", "Not Deprecated", "abc", None, "module_name")
]; ];
let expected = vec![Lint::new(
"should_assert_eq2",
"Not Deprecated",
"abc",
None,
"module_name",
)];
assert_eq!(expected, Lint::usable_lints(lints.into_iter()).collect::<Vec<Lint>>()); assert_eq!(expected, Lint::usable_lints(lints.into_iter()).collect::<Vec<Lint>>());
} }
@ -368,13 +397,17 @@ fn test_by_lint_group() {
Lint::new("incorrect_match", "group1", "abc", None, "module_name"), Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
]; ];
let mut expected: HashMap<String, Vec<Lint>> = HashMap::new(); let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
expected.insert("group1".to_string(), vec![ expected.insert(
"group1".to_string(),
vec![
Lint::new("should_assert_eq", "group1", "abc", None, "module_name"), Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
Lint::new("incorrect_match", "group1", "abc", None, "module_name"), Lint::new("incorrect_match", "group1", "abc", None, "module_name"),
]); ],
expected.insert("group2".to_string(), vec![ );
Lint::new("should_assert_eq2", "group2", "abc", None, "module_name") expected.insert(
]); "group2".to_string(),
vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")],
);
assert_eq!(expected, Lint::by_lint_group(&lints)); assert_eq!(expected, Lint::by_lint_group(&lints));
} }
@ -387,7 +420,7 @@ fn test_gen_changelog_lint_list() {
]; ];
let expected = vec![ let expected = vec![
format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()), format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()),
format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()) format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()),
]; ];
assert_eq!(expected, gen_changelog_lint_list(lints)); assert_eq!(expected, gen_changelog_lint_list(lints));
} }
@ -395,9 +428,21 @@ fn test_gen_changelog_lint_list() {
#[test] #[test]
fn test_gen_deprecated() { fn test_gen_deprecated() {
let lints = vec![ let lints = vec![
Lint::new("should_assert_eq", "group1", "abc", Some("has been superseeded by should_assert_eq2"), "module_name"), Lint::new(
Lint::new("another_deprecated", "group2", "abc", Some("will be removed"), "module_name"), "should_assert_eq",
Lint::new("should_assert_eq2", "group2", "abc", None, "module_name") "group1",
"abc",
Some("has been superseeded by should_assert_eq2"),
"module_name",
),
Lint::new(
"another_deprecated",
"group2",
"abc",
Some("will be removed"),
"module_name",
),
Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
]; ];
let expected: Vec<String> = vec![ let expected: Vec<String> = vec![
" store.register_removed(", " store.register_removed(",
@ -407,8 +452,11 @@ fn test_gen_deprecated() {
" store.register_removed(", " store.register_removed(",
" \"another_deprecated\",", " \"another_deprecated\",",
" \"will be removed\",", " \"will be removed\",",
" );" " );",
].into_iter().map(String::from).collect(); ]
.into_iter()
.map(String::from)
.collect();
assert_eq!(expected, gen_deprecated(&lints)); assert_eq!(expected, gen_deprecated(&lints));
} }

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
extern crate clap; extern crate clap;
extern crate clippy_dev; extern crate clippy_dev;
extern crate regex; extern crate regex;
@ -18,29 +17,31 @@ use clippy_dev::*;
#[derive(PartialEq)] #[derive(PartialEq)]
enum UpdateMode { enum UpdateMode {
Check, Check,
Change Change,
} }
fn main() { fn main() {
let matches = App::new("Clippy developer tooling") let matches = App::new("Clippy developer tooling")
.subcommand( .subcommand(
SubCommand::with_name("update_lints") SubCommand::with_name("update_lints")
.about("Makes sure that:\n \ .about(
"Makes sure that:\n \
* the lint count in README.md is correct\n \ * the lint count in README.md is correct\n \
* the changelog contains markdown link references at the bottom\n \ * the changelog contains markdown link references at the bottom\n \
* all lint groups include the correct lints\n \ * all lint groups include the correct lints\n \
* lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \ * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
* all lints are registered in the lint store") * all lints are registered in the lint store",
.arg(
Arg::with_name("print-only")
.long("print-only")
.help("Print a table of lints to STDOUT. This does not include deprecated and internal lints. (Does not modify any files)")
) )
.arg(Arg::with_name("print-only").long("print-only").help(
"Print a table of lints to STDOUT. \
This does not include deprecated and internal lints. \
(Does not modify any files)",
))
.arg( .arg(
Arg::with_name("check") Arg::with_name("check")
.long("check") .long("check")
.help("Checks that util/dev update_lints has been run. Used on CI."), .help("Checks that util/dev update_lints has been run. Used on CI."),
) ),
) )
.get_matches(); .get_matches();
@ -62,13 +63,21 @@ fn print_lints() {
let grouped_by_lint_group = Lint::by_lint_group(&usable_lints); let grouped_by_lint_group = Lint::by_lint_group(&usable_lints);
for (lint_group, mut lints) in grouped_by_lint_group { for (lint_group, mut lints) in grouped_by_lint_group {
if lint_group == "Deprecated" { continue; } if lint_group == "Deprecated" {
continue;
}
println!("\n## {}", lint_group); println!("\n## {}", lint_group);
lints.sort_by_key(|l| l.name.clone()); lints.sort_by_key(|l| l.name.clone());
for lint in lints { for lint in lints {
println!("* [{}]({}#{}) ({})", lint.name, clippy_dev::DOCS_LINK.clone(), lint.name, lint.desc); println!(
"* [{}]({}#{}) ({})",
lint.name,
clippy_dev::DOCS_LINK.clone(),
lint.name,
lint.desc
);
} }
} }
@ -99,8 +108,9 @@ fn update_lints(update_mode: &UpdateMode) {
"<!-- end autogenerated links to lint list -->", "<!-- end autogenerated links to lint list -->",
false, false,
update_mode == &UpdateMode::Change, update_mode == &UpdateMode::Change,
|| { gen_changelog_lint_list(lint_list.clone()) } || gen_changelog_lint_list(lint_list.clone()),
).changed; )
.changed;
file_change |= replace_region_in_file( file_change |= replace_region_in_file(
"../clippy_lints/src/lib.rs", "../clippy_lints/src/lib.rs",
@ -108,8 +118,9 @@ fn update_lints(update_mode: &UpdateMode) {
"end deprecated lints", "end deprecated lints",
false, false,
update_mode == &UpdateMode::Change, update_mode == &UpdateMode::Change,
|| { gen_deprecated(&lint_list) } || gen_deprecated(&lint_list),
).changed; )
.changed;
file_change |= replace_region_in_file( file_change |= replace_region_in_file(
"../clippy_lints/src/lib.rs", "../clippy_lints/src/lib.rs",
@ -117,8 +128,9 @@ fn update_lints(update_mode: &UpdateMode) {
"end lints modules", "end lints modules",
false, false,
update_mode == &UpdateMode::Change, update_mode == &UpdateMode::Change,
|| { gen_modules_list(lint_list.clone()) } || gen_modules_list(lint_list.clone()),
).changed; )
.changed;
// Generate lists of lints in the clippy::all lint group // Generate lists of lints in the clippy::all lint group
file_change |= replace_region_in_file( file_change |= replace_region_in_file(
@ -129,16 +141,18 @@ fn update_lints(update_mode: &UpdateMode) {
update_mode == &UpdateMode::Change, update_mode == &UpdateMode::Change,
|| { || {
// clippy::all should only include the following lint groups: // clippy::all should only include the following lint groups:
let all_group_lints = usable_lints.clone().into_iter().filter(|l| { let all_group_lints = usable_lints
l.group == "correctness" || .clone()
l.group == "style" || .into_iter()
l.group == "complexity" || .filter(|l| {
l.group == "perf" l.group == "correctness" || l.group == "style" || l.group == "complexity" || l.group == "perf"
}).collect(); })
.collect();
gen_lint_group_list(all_group_lints) gen_lint_group_list(all_group_lints)
} },
).changed; )
.changed;
// Generate the list of lints for all other lint groups // Generate the list of lints for all other lint groups
for (lint_group, lints) in Lint::by_lint_group(&usable_lints) { for (lint_group, lints) in Lint::by_lint_group(&usable_lints) {
@ -148,12 +162,16 @@ fn update_lints(update_mode: &UpdateMode) {
r#"\]\);"#, r#"\]\);"#,
false, false,
update_mode == &UpdateMode::Change, update_mode == &UpdateMode::Change,
|| { gen_lint_group_list(lints.clone()) } || gen_lint_group_list(lints.clone()),
).changed; )
.changed;
} }
if update_mode == &UpdateMode::Check && file_change { if update_mode == &UpdateMode::Check && file_change {
println!("Not all lints defined properly. Please run `util/dev update_lints` to make sure all lints are defined properly."); println!(
"Not all lints defined properly. \
Please run `util/dev update_lints` to make sure all lints are defined properly."
);
std::process::exit(1); std::process::exit(1);
} }
} }

View file

@ -7,14 +7,13 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::utils::span_lint;
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use std::f64::consts as f64;
use crate::syntax::ast::{FloatTy, Lit, LitKind}; use crate::syntax::ast::{FloatTy, Lit, LitKind};
use crate::syntax::symbol; use crate::syntax::symbol;
use crate::utils::span_lint;
use std::f64::consts as f64;
/// **What it does:** Checks for floating point literals that approximate /// **What it does:** Checks for floating point literals that approximate
/// constants which are defined in /// constants which are defined in

View file

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::utils::span_lint;
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::span_lint;
/// **What it does:** Checks for plain integer arithmetic. /// **What it does:** Checks for plain integer arithmetic.
/// ///
@ -52,7 +51,8 @@ declare_clippy_lint! {
#[derive(Copy, Clone, Default)] #[derive(Copy, Clone, Default)]
pub struct Arithmetic { pub struct Arithmetic {
expr_span: Option<Span>, expr_span: Option<Span>,
/// This field is used to check whether expressions are constants, such as in enum discriminants and consts /// This field is used to check whether expressions are constants, such as in enum discriminants
/// and consts
const_span: Option<Span>, const_span: Option<Span>,
} }
@ -124,8 +124,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic {
let body_owner = cx.tcx.hir.body_owner(body.id()); let body_owner = cx.tcx.hir.body_owner(body.id());
match cx.tcx.hir.body_owner_kind(body_owner) { match cx.tcx.hir.body_owner_kind(body_owner) {
hir::BodyOwnerKind::Static(_) hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => {
| hir::BodyOwnerKind::Const => {
let body_span = cx.tcx.hir.span(body_owner); let body_span = cx.tcx.hir.span(body_owner);
if let Some(span) = self.const_span { if let Some(span) = self.const_span {
@ -134,7 +133,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic {
} }
} }
self.const_span = Some(body_span); self.const_span = Some(body_span);
} },
hir::BodyOwnerKind::Fn => (), hir::BodyOwnerKind::Fn => (),
} }
} }

View file

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::utils::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq};
use crate::utils::{higher, sugg};
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::syntax::ast;
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::syntax::ast;
use crate::utils::{get_trait_def_id, implements_trait, snippet_opt, span_lint_and_then, SpanlessEq};
use crate::utils::{higher, sugg};
use if_chain::if_chain;
/// **What it does:** Checks for `a = a op b` or `a = b commutative_op a` /// **What it does:** Checks for `a = a op b` or `a = b commutative_op a`
/// patterns. /// patterns.
@ -217,7 +216,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
// a = b commutative_op a // a = b commutative_op a
// Limited to primitive type as these ops are know to be commutative // Limited to primitive type as these ops are know to be commutative
if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r) if SpanlessEq::new(cx).ignore_fn().eq_expr(assignee, r)
&& cx.tables.expr_ty(assignee).is_primitive_ty() { && cx.tables.expr_ty(assignee).is_primitive_ty()
{
match op.node { match op.node {
hir::BinOpKind::Add hir::BinOpKind::Add
| hir::BinOpKind::Mul | hir::BinOpKind::Mul

View file

@ -7,27 +7,24 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! checks for attributes //! checks for attributes
use crate::reexport::*; use crate::reexport::*;
use crate::utils::{
in_macro, last_line_of_span, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_sugg,
span_lint_and_then, without_block_comments,
};
use if_chain::if_chain;
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{ use crate::rustc::lint::{
CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintContext, LintPass, CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintContext, LintPass,
}; };
use crate::rustc::ty::{self, TyCtxt}; use crate::rustc::ty::{self, TyCtxt};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use semver::Version;
use crate::syntax::ast::{
AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind,
};
use crate::syntax::source_map::Span;
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::syntax::ast::{AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
use crate::syntax::source_map::Span;
use crate::utils::{
in_macro, last_line_of_span, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_sugg,
span_lint_and_then, without_block_comments,
};
use if_chain::if_chain;
use semver::Version;
/// **What it does:** Checks for items annotated with `#[inline(always)]`, /// **What it does:** Checks for items annotated with `#[inline(always)]`,
/// unless the annotated function is empty or simply panics. /// unless the annotated function is empty or simply panics.
@ -219,8 +216,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
match &*attr.name().as_str() { match &*attr.name().as_str() {
"allow" | "warn" | "deny" | "forbid" => { "allow" | "warn" | "deny" | "forbid" => {
check_clippy_lint_names(cx, items); check_clippy_lint_names(cx, items);
} },
_ => {} _ => {},
} }
if items.is_empty() || attr.name() != "deprecated" { if items.is_empty() || attr.name() != "deprecated" {
return; return;
@ -254,19 +251,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
// and `unused_imports` for `extern crate` items with `macro_use` // and `unused_imports` for `extern crate` items with `macro_use`
for lint in lint_list { for lint in lint_list {
match item.node { match item.node {
ItemKind::Use(..) => if is_word(lint, "unused_imports") ItemKind::Use(..) => {
|| is_word(lint, "deprecated") { if is_word(lint, "unused_imports") || is_word(lint, "deprecated") {
return return;
}
}, },
ItemKind::ExternCrate(..) => { ItemKind::ExternCrate(..) => {
if is_word(lint, "unused_imports") if is_word(lint, "unused_imports") && skip_unused_imports {
&& skip_unused_imports { return;
return
} }
if is_word(lint, "unused_extern_crates") { if is_word(lint, "unused_extern_crates") {
return return;
}
} }
},
_ => {}, _ => {},
} }
} }
@ -396,7 +393,8 @@ fn is_relevant_expr(tcx: TyCtxt<'_, '_, '_>, tables: &ty::TypeckTables<'_>, expr
ExprKind::Block(ref block, _) => is_relevant_block(tcx, tables, block), ExprKind::Block(ref block, _) => is_relevant_block(tcx, tables, block),
ExprKind::Ret(Some(ref e)) => is_relevant_expr(tcx, tables, e), ExprKind::Ret(Some(ref e)) => is_relevant_expr(tcx, tables, e),
ExprKind::Ret(None) | ExprKind::Break(_, None) => false, ExprKind::Ret(None) | ExprKind::Break(_, None) => false,
ExprKind::Call(ref path_expr, _) => if let ExprKind::Path(ref qpath) = path_expr.node { ExprKind::Call(ref path_expr, _) => {
if let ExprKind::Path(ref qpath) = path_expr.node {
if let Some(fun_id) = opt_def_id(tables.qpath_def(qpath, path_expr.hir_id)) { if let Some(fun_id) = opt_def_id(tables.qpath_def(qpath, path_expr.hir_id)) {
!match_def_path(tcx, fun_id, &paths::BEGIN_PANIC) !match_def_path(tcx, fun_id, &paths::BEGIN_PANIC)
} else { } else {
@ -404,6 +402,7 @@ fn is_relevant_expr(tcx: TyCtxt<'_, '_, '_>, tables: &ty::TypeckTables<'_>, expr
} }
} else { } else {
true true
}
}, },
_ => true, _ => true,
} }
@ -435,7 +434,8 @@ fn check_attrs(cx: &LateContext<'_, '_>, span: Span, name: Name, attrs: &[Attrib
cx, cx,
EMPTY_LINE_AFTER_OUTER_ATTR, EMPTY_LINE_AFTER_OUTER_ATTR,
begin_of_attr_to_item, 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?" "Found an empty line after an outer attribute. \
Perhaps you forgot to add a '!' to make it an inner attribute?",
); );
} }
} }
@ -501,9 +501,7 @@ pub struct CfgAttrPass;
impl LintPass for CfgAttrPass { impl LintPass for CfgAttrPass {
fn get_lints(&self) -> LintArray { fn get_lints(&self) -> LintArray {
lint_array!( lint_array!(DEPRECATED_CFG_ATTR,)
DEPRECATED_CFG_ATTR,
)
} }
} }

View file

@ -7,17 +7,16 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::consts::{constant, Constant};
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain; use crate::rustc_errors::Applicability;
use crate::syntax::ast::LitKind; use crate::syntax::ast::LitKind;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::{span_lint, span_lint_and_then};
use crate::utils::sugg::Sugg; use crate::utils::sugg::Sugg;
use crate::consts::{constant, Constant}; use crate::utils::{span_lint, span_lint_and_then};
use crate::rustc_errors::Applicability; use if_chain::if_chain;
/// **What it does:** Checks for incompatible bit masks in comparisons. /// **What it does:** Checks for incompatible bit masks in comparisons.
/// ///
@ -173,7 +172,6 @@ fn invert_cmp(cmp: BinOpKind) -> BinOpKind {
} }
} }
fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr, cmp_op: BinOpKind, cmp_value: u128, span: Span) { fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr, cmp_op: BinOpKind, cmp_value: u128, span: Span) {
if let ExprKind::Binary(ref op, ref left, ref right) = bit_op.node { if let ExprKind::Binary(ref op, ref left, ref right) = bit_op.node {
if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr { if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr {
@ -185,10 +183,18 @@ fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr, cmp_op: BinOpKind, cmp
} }
} }
fn check_bit_mask(cx: &LateContext<'_, '_>, bit_op: BinOpKind, cmp_op: BinOpKind, mask_value: u128, cmp_value: u128, span: Span) { fn check_bit_mask(
cx: &LateContext<'_, '_>,
bit_op: BinOpKind,
cmp_op: BinOpKind,
mask_value: u128,
cmp_value: u128,
span: Span,
) {
match cmp_op { match cmp_op {
BinOpKind::Eq | BinOpKind::Ne => match bit_op { BinOpKind::Eq | BinOpKind::Ne => match bit_op {
BinOpKind::BitAnd => if mask_value & cmp_value != cmp_value { BinOpKind::BitAnd => {
if mask_value & cmp_value != cmp_value {
if cmp_value != 0 { if cmp_value != 0 {
span_lint( span_lint(
cx, cx,
@ -196,88 +202,93 @@ fn check_bit_mask(cx: &LateContext<'_, '_>, bit_op: BinOpKind, cmp_op: BinOpKind
span, span,
&format!( &format!(
"incompatible bit mask: `_ & {}` can never be equal to `{}`", "incompatible bit mask: `_ & {}` can never be equal to `{}`",
mask_value, mask_value, cmp_value
cmp_value
), ),
); );
} }
} else if mask_value == 0 { } else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
}
}, },
BinOpKind::BitOr => if mask_value | cmp_value != cmp_value { BinOpKind::BitOr => {
if mask_value | cmp_value != cmp_value {
span_lint( span_lint(
cx, cx,
BAD_BIT_MASK, BAD_BIT_MASK,
span, span,
&format!( &format!(
"incompatible bit mask: `_ | {}` can never be equal to `{}`", "incompatible bit mask: `_ | {}` can never be equal to `{}`",
mask_value, mask_value, cmp_value
cmp_value
), ),
); );
}
}, },
_ => (), _ => (),
}, },
BinOpKind::Lt | BinOpKind::Ge => match bit_op { BinOpKind::Lt | BinOpKind::Ge => match bit_op {
BinOpKind::BitAnd => if mask_value < cmp_value { BinOpKind::BitAnd => {
if mask_value < cmp_value {
span_lint( span_lint(
cx, cx,
BAD_BIT_MASK, BAD_BIT_MASK,
span, span,
&format!( &format!(
"incompatible bit mask: `_ & {}` will always be lower than `{}`", "incompatible bit mask: `_ & {}` will always be lower than `{}`",
mask_value, mask_value, cmp_value
cmp_value
), ),
); );
} else if mask_value == 0 { } else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
}
}, },
BinOpKind::BitOr => if mask_value >= cmp_value { BinOpKind::BitOr => {
if mask_value >= cmp_value {
span_lint( span_lint(
cx, cx,
BAD_BIT_MASK, BAD_BIT_MASK,
span, span,
&format!( &format!(
"incompatible bit mask: `_ | {}` will never be lower than `{}`", "incompatible bit mask: `_ | {}` will never be lower than `{}`",
mask_value, mask_value, cmp_value
cmp_value
), ),
); );
} else { } else {
check_ineffective_lt(cx, span, mask_value, cmp_value, "|"); check_ineffective_lt(cx, span, mask_value, cmp_value, "|");
}
}, },
BinOpKind::BitXor => check_ineffective_lt(cx, span, mask_value, cmp_value, "^"), BinOpKind::BitXor => check_ineffective_lt(cx, span, mask_value, cmp_value, "^"),
_ => (), _ => (),
}, },
BinOpKind::Le | BinOpKind::Gt => match bit_op { BinOpKind::Le | BinOpKind::Gt => match bit_op {
BinOpKind::BitAnd => if mask_value <= cmp_value { BinOpKind::BitAnd => {
if mask_value <= cmp_value {
span_lint( span_lint(
cx, cx,
BAD_BIT_MASK, BAD_BIT_MASK,
span, span,
&format!( &format!(
"incompatible bit mask: `_ & {}` will never be higher than `{}`", "incompatible bit mask: `_ & {}` will never be higher than `{}`",
mask_value, mask_value, cmp_value
cmp_value
), ),
); );
} else if mask_value == 0 { } else if mask_value == 0 {
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero"); span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
}
}, },
BinOpKind::BitOr => if mask_value > cmp_value { BinOpKind::BitOr => {
if mask_value > cmp_value {
span_lint( span_lint(
cx, cx,
BAD_BIT_MASK, BAD_BIT_MASK,
span, span,
&format!( &format!(
"incompatible bit mask: `_ | {}` will always be higher than `{}`", "incompatible bit mask: `_ | {}` will always be higher than `{}`",
mask_value, mask_value, cmp_value
cmp_value
), ),
); );
} else { } else {
check_ineffective_gt(cx, span, mask_value, cmp_value, "|"); check_ineffective_gt(cx, span, mask_value, cmp_value, "|");
}
}, },
BinOpKind::BitXor => check_ineffective_gt(cx, span, mask_value, cmp_value, "^"), BinOpKind::BitXor => check_ineffective_gt(cx, span, mask_value, cmp_value, "^"),
_ => (), _ => (),
@ -294,9 +305,7 @@ fn check_ineffective_lt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128,
span, span,
&format!( &format!(
"ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
op, op, m, c
m,
c
), ),
); );
} }
@ -310,9 +319,7 @@ fn check_ineffective_gt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128,
span, span,
&format!( &format!(
"ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly", "ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
op, op, m, c
m,
c
), ),
); );
} }

View file

@ -7,10 +7,9 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::utils::span_lint; use crate::utils::span_lint;
/// **What it does:** Checks for usage of blacklisted names for variables, such /// **What it does:** Checks for usage of blacklisted names for variables, such
@ -38,9 +37,7 @@ pub struct BlackListedName {
impl BlackListedName { impl BlackListedName {
pub fn new(blacklist: Vec<String>) -> Self { pub fn new(blacklist: Vec<String>) -> Self {
Self { Self { blacklist }
blacklist,
}
} }
} }

View file

@ -7,13 +7,12 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use matches::matches; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::utils::*; use crate::utils::*;
use matches::matches;
/// **What it does:** Checks for `if` conditions that use blocks to contain an /// **What it does:** Checks for `if` conditions that use blocks to contain an
/// expression. /// expression.
@ -112,10 +111,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
); );
} }
} else { } else {
let span = block let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
.expr
.as_ref()
.map_or_else(|| block.stmts[0].span, |e| e.span);
if in_macro(span) || differing_macro_contexts(expr.span, span) { if in_macro(span) || differing_macro_contexts(expr.span, span) {
return; return;
} }
@ -134,10 +130,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
} }
} }
} else { } else {
let mut visitor = ExVisitor { let mut visitor = ExVisitor { found_block: None, cx };
found_block: None,
cx,
};
walk_expr(&mut visitor, check); walk_expr(&mut visitor, check);
if let Some(block) = visitor.found_block { if let Some(block) = visitor.found_block {
span_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE); span_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE);

View file

@ -7,16 +7,17 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::intravisit::*;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*; use crate::rustc_data_structures::thin_vec::ThinVec;
use crate::rustc::hir::intravisit::*; use crate::rustc_errors::Applicability;
use crate::syntax::ast::{LitKind, NodeId, DUMMY_NODE_ID}; use crate::syntax::ast::{LitKind, NodeId, DUMMY_NODE_ID};
use crate::syntax::source_map::{dummy_spanned, Span, DUMMY_SP}; use crate::syntax::source_map::{dummy_spanned, Span, DUMMY_SP};
use crate::rustc_data_structures::thin_vec::ThinVec; use crate::utils::{
use crate::utils::{in_macro, paths, match_type, snippet_opt, span_lint_and_then, SpanlessEq, get_trait_def_id, implements_trait}; get_trait_def_id, implements_trait, in_macro, match_type, paths, snippet_opt, span_lint_and_then, SpanlessEq,
use crate::rustc_errors::Applicability; };
/// **What it does:** Checks for boolean expressions that can be written more /// **What it does:** Checks for boolean expressions that can be written more
/// concisely. /// concisely.
@ -57,10 +58,7 @@ declare_clippy_lint! {
} }
// For each pairs, both orders are considered. // For each pairs, both orders are considered.
const METHODS_WITH_NEGATION: [(&str, &str); 2] = [ const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")];
("is_some", "is_none"),
("is_err", "is_ok"),
];
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct NonminimalBool; pub struct NonminimalBool;
@ -134,19 +132,16 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
} }
let negated = match e.node { let negated = match e.node {
ExprKind::Binary(binop, ref lhs, ref rhs) => { ExprKind::Binary(binop, ref lhs, ref rhs) => {
if !implements_ord(self.cx, lhs) { if !implements_ord(self.cx, lhs) {
continue; continue;
} }
let mk_expr = |op| { let mk_expr = |op| Expr {
Expr {
id: DUMMY_NODE_ID, id: DUMMY_NODE_ID,
hir_id: DUMMY_HIR_ID, hir_id: DUMMY_HIR_ID,
span: DUMMY_SP, span: DUMMY_SP,
attrs: ThinVec::new(), attrs: ThinVec::new(),
node: ExprKind::Binary(dummy_spanned(op), lhs.clone(), rhs.clone()), node: ExprKind::Binary(dummy_spanned(op), lhs.clone(), rhs.clone()),
}
}; };
match binop.node { match binop.node {
BinOpKind::Eq => mk_expr(BinOpKind::Ne), BinOpKind::Eq => mk_expr(BinOpKind::Ne),
@ -191,7 +186,6 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
fn simplify_not(&self, expr: &Expr) -> Option<String> { fn simplify_not(&self, expr: &Expr) -> Option<String> {
match expr.node { match expr.node {
ExprKind::Binary(binop, ref lhs, ref rhs) => { ExprKind::Binary(binop, ref lhs, ref rhs) => {
if !implements_ord(self.cx, lhs) { if !implements_ord(self.cx, lhs) {
return None; return None;
} }
@ -204,16 +198,19 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
BinOpKind::Le => Some(" > "), BinOpKind::Le => Some(" > "),
BinOpKind::Ge => Some(" < "), BinOpKind::Ge => Some(" < "),
_ => None, _ => None,
}.and_then(|op| Some(format!("{}{}{}", self.snip(lhs)?, op, self.snip(rhs)?))) }
.and_then(|op| Some(format!("{}{}{}", self.snip(lhs)?, op, self.snip(rhs)?)))
}, },
ExprKind::MethodCall(ref path, _, ref args) if args.len() == 1 => { ExprKind::MethodCall(ref path, _, ref args) if args.len() == 1 => {
let type_of_receiver = self.cx.tables.expr_ty(&args[0]); let type_of_receiver = self.cx.tables.expr_ty(&args[0]);
if !match_type(self.cx, type_of_receiver, &paths::OPTION) && if !match_type(self.cx, type_of_receiver, &paths::OPTION)
!match_type(self.cx, type_of_receiver, &paths::RESULT) { && !match_type(self.cx, type_of_receiver, &paths::RESULT)
{
return None; return None;
} }
METHODS_WITH_NEGATION METHODS_WITH_NEGATION
.iter().cloned() .iter()
.cloned()
.flat_map(|(a, b)| vec![(a, b), (b, a)]) .flat_map(|(a, b)| vec![(a, b), (b, a)])
.find(|&(a, _)| a == path.ident.as_str()) .find(|&(a, _)| a == path.ident.as_str())
.and_then(|(_, neg_method)| Some(format!("{}.{}()", self.snip(&args[0])?, neg_method))) .and_then(|(_, neg_method)| Some(format!("{}.{}()", self.snip(&args[0])?, neg_method)))
@ -452,7 +449,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
improvements improvements
.into_iter() .into_iter()
.map(|suggestion| suggest(self.cx, suggestion, &h2q.terminals).0) .map(|suggestion| suggest(self.cx, suggestion, &h2q.terminals).0)
.collect() .collect(),
); );
} }
} }
@ -465,11 +462,15 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
return; return;
} }
match e.node { match e.node {
ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => self.bool_expr(e), ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
ExprKind::Unary(UnNot, ref inner) => if self.cx.tables.node_types()[inner.hir_id].is_bool() { self.bool_expr(e)
},
ExprKind::Unary(UnNot, ref inner) => {
if self.cx.tables.node_types()[inner.hir_id].is_bool() {
self.bool_expr(e); self.bool_expr(e);
} else { } else {
walk_expr(self, e); walk_expr(self, e);
}
}, },
_ => walk_expr(self, e), _ => walk_expr(self, e),
} }
@ -479,9 +480,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
} }
} }
fn implements_ord<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, expr: &Expr) -> bool { fn implements_ord<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, expr: &Expr) -> bool {
let ty = cx.tables.expr_ty(expr); let ty = cx.tables.expr_ty(expr);
get_trait_def_id(cx, &paths::ORD) get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]))
.map_or(false, |id| implements_trait(cx, ty, id, &[]))
} }

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty; use crate::rustc::ty;
@ -118,10 +117,12 @@ fn check_arg(name: Name, arg: Name, needle: &Expr) -> bool {
fn get_path_name(expr: &Expr) -> Option<Name> { fn get_path_name(expr: &Expr) -> Option<Name> {
match expr.node { match expr.node {
ExprKind::Box(ref e) | ExprKind::AddrOf(_, ref e) | ExprKind::Unary(UnOp::UnDeref, ref e) => get_path_name(e), ExprKind::Box(ref e) | ExprKind::AddrOf(_, ref e) | ExprKind::Unary(UnOp::UnDeref, ref e) => get_path_name(e),
ExprKind::Block(ref b, _) => if b.stmts.is_empty() { ExprKind::Block(ref b, _) => {
if b.stmts.is_empty() {
b.expr.as_ref().and_then(|p| get_path_name(p)) b.expr.as_ref().and_then(|p| get_path_name(p))
} else { } else {
None None
}
}, },
ExprKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name), ExprKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
_ => None, _ => None,

View file

@ -56,7 +56,7 @@ fn is_empty_str(value: &Option<String>) -> bool {
match value { match value {
None => true, None => true,
Some(value) if value.is_empty() => true, Some(value) if value.is_empty() => true,
_ => false _ => false,
} }
} }

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! Checks for if expressions that contain only an if expression. //! Checks for if expressions that contain only an if expression.
//! //!
//! For example, the lint would catch: //! For example, the lint would catch:
@ -24,12 +23,12 @@
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::syntax::ast; use crate::syntax::ast;
use if_chain::if_chain;
use crate::utils::{in_macro, snippet_block, snippet_block_with_applicability, span_lint_and_sugg, span_lint_and_then};
use crate::utils::sugg::Sugg;
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::utils::sugg::Sugg;
use crate::utils::{in_macro, snippet_block, snippet_block_with_applicability, span_lint_and_sugg, span_lint_and_then};
/// **What it does:** Checks for nested `if` statements which can be collapsed /// **What it does:** Checks for nested `if` statements which can be collapsed
/// by `&&`-combining their conditions and for `else { if ... }` expressions /// by `&&`-combining their conditions and for `else { if ... }` expressions
@ -100,10 +99,12 @@ impl EarlyLintPass for CollapsibleIf {
fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) { fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
match expr.node { match expr.node {
ast::ExprKind::If(ref check, ref then, ref else_) => if let Some(ref else_) = *else_ { ast::ExprKind::If(ref check, ref then, ref else_) => {
if let Some(ref else_) = *else_ {
check_collapsible_maybe_if_let(cx, else_); check_collapsible_maybe_if_let(cx, else_);
} else { } else {
check_collapsible_no_if_let(cx, expr, check, then); check_collapsible_no_if_let(cx, expr, check, then);
}
}, },
ast::ExprKind::IfLet(_, _, _, Some(ref else_)) => { ast::ExprKind::IfLet(_, _, _, Some(ref else_)) => {
check_collapsible_maybe_if_let(cx, else_); check_collapsible_maybe_if_let(cx, else_);
@ -114,8 +115,9 @@ fn check_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
fn block_starts_with_comment(cx: &EarlyContext<'_>, expr: &ast::Block) -> bool { fn block_starts_with_comment(cx: &EarlyContext<'_>, expr: &ast::Block) -> bool {
// We trim all opening braces and whitespaces and then check if the next string is a comment. // We trim all opening braces and whitespaces and then check if the next string is a comment.
let trimmed_block_text = let trimmed_block_text = snippet_block(cx, expr.span, "..")
snippet_block(cx, expr.span, "..").trim_left_matches(|c: char| c.is_whitespace() || c == '{').to_owned(); .trim_left_matches(|c: char| c.is_whitespace() || c == '{')
.to_owned();
trimmed_block_text.starts_with("//") || trimmed_block_text.starts_with("/*") trimmed_block_text.starts_with("//") || trimmed_block_text.starts_with("/*")
} }

View file

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::syntax::ast::*;
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{in_macro, snippet, span_lint_and_then};
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::syntax::ast::*;
use crate::utils::{in_macro, snippet, span_lint_and_then};
/// **What it does:** Checks for constants with an explicit `'static` lifetime. /// **What it does:** Checks for constants with an explicit `'static` lifetime.
/// ///
@ -52,16 +51,17 @@ impl StaticConst {
TyKind::Array(ref ty, _) => { TyKind::Array(ref ty, _) => {
self.visit_type(&*ty, cx); self.visit_type(&*ty, cx);
}, },
TyKind::Tup(ref tup) => for tup_ty in tup { TyKind::Tup(ref tup) => {
for tup_ty in tup {
self.visit_type(&*tup_ty, cx); self.visit_type(&*tup_ty, cx);
}
}, },
// This is what we are looking for ! // This is what we are looking for !
TyKind::Rptr(ref optional_lifetime, ref borrow_type) => { TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
// Match the 'static lifetime // Match the 'static lifetime
if let Some(lifetime) = *optional_lifetime { if let Some(lifetime) = *optional_lifetime {
match borrow_type.ty.node { match borrow_type.ty.node {
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
TyKind::Tup(..) => {
if lifetime.ident.name == "'static" { if lifetime.ident.name == "'static" {
let snip = snippet(cx, borrow_type.ty.span, "<type>"); let snip = snippet(cx, borrow_type.ty.span, "<type>");
let sugg = format!("&{}", snip); let sugg = format!("&{}", snip);
@ -80,8 +80,8 @@ impl StaticConst {
}, },
); );
} }
} },
_ => {} _ => {},
} }
} }
self.visit_type(&*borrow_type.ty, cx); self.visit_type(&*borrow_type.ty, cx);

View file

@ -10,21 +10,21 @@
#![allow(clippy::float_cmp)] #![allow(clippy::float_cmp)]
use crate::rustc::lint::LateContext;
use crate::rustc::{span_bug, bug};
use crate::rustc::hir::def::Def; use crate::rustc::hir::def::Def;
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::ty::{self, Ty, TyCtxt, Instance}; use crate::rustc::lint::LateContext;
use crate::rustc::ty::subst::{Subst, Substs}; use crate::rustc::ty::subst::{Subst, Substs};
use crate::rustc::ty::{self, Instance, Ty, TyCtxt};
use crate::rustc::{bug, span_bug};
use crate::syntax::ast::{FloatTy, LitKind};
use crate::syntax::ptr::P;
use crate::utils::{clip, sext, unsext};
use std::cmp::Ordering::{self, Equal}; use std::cmp::Ordering::{self, Equal};
use std::cmp::PartialOrd; use std::cmp::PartialOrd;
use std::convert::TryInto; use std::convert::TryInto;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem; use std::mem;
use std::rc::Rc; use std::rc::Rc;
use crate::syntax::ast::{FloatTy, LitKind};
use crate::syntax::ptr::P;
use crate::utils::{sext, unsext, clip};
/// A `LitKind`-like enum to fold constant `Expr`s into. /// A `LitKind`-like enum to fold constant `Expr`s into.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -71,7 +71,9 @@ impl PartialEq for Constant {
unsafe { mem::transmute::<f64, u64>(f64::from(l)) == mem::transmute::<f64, u64>(f64::from(r)) } unsafe { mem::transmute::<f64, u64>(f64::from(l)) == mem::transmute::<f64, u64>(f64::from(r)) }
}, },
(&Constant::Bool(l), &Constant::Bool(r)) => l == r, (&Constant::Bool(l), &Constant::Bool(r)) => l == r,
(&Constant::Vec(ref l), &Constant::Vec(ref r)) | (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => l == r, (&Constant::Vec(ref l), &Constant::Vec(ref r)) | (&Constant::Tuple(ref l), &Constant::Tuple(ref r)) => {
l == r
},
(&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => ls == rs && lv == rv, (&Constant::Repeat(ref lv, ref ls), &Constant::Repeat(ref rv, ref rs)) => ls == rs && lv == rv,
_ => false, // TODO: Are there inter-type equalities? _ => false, // TODO: Are there inter-type equalities?
} }
@ -117,7 +119,12 @@ impl Hash for Constant {
} }
impl Constant { impl Constant {
pub fn partial_cmp(tcx: TyCtxt<'_, '_, '_>, cmp_type: &ty::TyKind<'_>, left: &Self, right: &Self) -> Option<Ordering> { pub fn partial_cmp(
tcx: TyCtxt<'_, '_, '_>,
cmp_type: &ty::TyKind<'_>,
left: &Self,
right: &Self,
) -> Option<Ordering> {
match (left, right) { match (left, right) {
(&Constant::Str(ref ls), &Constant::Str(ref rs)) => Some(ls.cmp(rs)), (&Constant::Str(ref ls), &Constant::Str(ref rs)) => Some(ls.cmp(rs)),
(&Constant::Char(ref l), &Constant::Char(ref r)) => Some(l.cmp(r)), (&Constant::Char(ref l), &Constant::Char(ref r)) => Some(l.cmp(r)),
@ -158,8 +165,7 @@ pub fn lit_to_constant<'tcx>(lit: &LitKind, ty: Ty<'tcx>) -> Constant {
LitKind::ByteStr(ref s) => Constant::Binary(Rc::clone(s)), LitKind::ByteStr(ref s) => Constant::Binary(Rc::clone(s)),
LitKind::Char(c) => Constant::Char(c), LitKind::Char(c) => Constant::Char(c),
LitKind::Int(n, _) => Constant::Int(n), LitKind::Int(n, _) => Constant::Int(n),
LitKind::Float(ref is, _) | LitKind::Float(ref is, _) | LitKind::FloatUnsuffixed(ref is) => match ty.sty {
LitKind::FloatUnsuffixed(ref is) => match ty.sty {
ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()), ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()), ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
_ => bug!(), _ => bug!(),
@ -168,7 +174,11 @@ pub fn lit_to_constant<'tcx>(lit: &LitKind, ty: Ty<'tcx>) -> Constant {
} }
} }
pub fn constant<'c, 'cc>(lcx: &LateContext<'c, 'cc>, tables: &'c ty::TypeckTables<'cc>, e: &Expr) -> Option<(Constant, bool)> { pub fn constant<'c, 'cc>(
lcx: &LateContext<'c, 'cc>,
tables: &'c ty::TypeckTables<'cc>,
e: &Expr,
) -> Option<(Constant, bool)> {
let mut cx = ConstEvalLateContext { let mut cx = ConstEvalLateContext {
tcx: lcx.tcx, tcx: lcx.tcx,
tables, tables,
@ -179,12 +189,19 @@ pub fn constant<'c, 'cc>(lcx: &LateContext<'c, 'cc>, tables: &'c ty::TypeckTable
cx.expr(e).map(|cst| (cst, cx.needed_resolution)) cx.expr(e).map(|cst| (cst, cx.needed_resolution))
} }
pub fn constant_simple<'c, 'cc>(lcx: &LateContext<'c, 'cc>, tables: &'c ty::TypeckTables<'cc>, e: &Expr) -> Option<Constant> { pub fn constant_simple<'c, 'cc>(
lcx: &LateContext<'c, 'cc>,
tables: &'c ty::TypeckTables<'cc>,
e: &Expr,
) -> Option<Constant> {
constant(lcx, tables, e).and_then(|(cst, res)| if res { None } else { Some(cst) }) constant(lcx, tables, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
} }
/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckTables` /// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckTables`
pub fn constant_context<'c, 'cc>(lcx: &LateContext<'c, 'cc>, tables: &'c ty::TypeckTables<'cc>) -> ConstEvalLateContext<'c, 'cc> { pub fn constant_context<'c, 'cc>(
lcx: &LateContext<'c, 'cc>,
tables: &'c ty::TypeckTables<'cc>,
) -> ConstEvalLateContext<'c, 'cc> {
ConstEvalLateContext { ConstEvalLateContext {
tcx: lcx.tcx, tcx: lcx.tcx,
tables, tables,
@ -270,9 +287,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
/// create `Some(Vec![..])` of all constants, unless there is any /// create `Some(Vec![..])` of all constants, unless there is any
/// non-constant part /// non-constant part
fn multi(&mut self, vec: &[Expr]) -> Option<Vec<Constant>> { fn multi(&mut self, vec: &[Expr]) -> Option<Vec<Constant>> {
vec.iter() vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
.map(|elem| self.expr(elem))
.collect::<Option<_>>()
} }
/// lookup a possibly constant expression from a ExprKind::Path /// lookup a possibly constant expression from a ExprKind::Path
@ -331,8 +346,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
let l = self.expr(left)?; let l = self.expr(left)?;
let r = self.expr(right); let r = self.expr(right);
match (l, r) { match (l, r) {
(Constant::Int(l), Some(Constant::Int(r))) => { (Constant::Int(l), Some(Constant::Int(r))) => match self.tables.expr_ty(left).sty {
match self.tables.expr_ty(left).sty {
ty::Int(ity) => { ty::Int(ity) => {
let l = sext(self.tcx, l, ity); let l = sext(self.tcx, l, ity);
let r = sext(self.tcx, r, ity); let r = sext(self.tcx, r, ity);
@ -343,12 +357,8 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
BinOpKind::Mul => l.checked_mul(r).map(zext), BinOpKind::Mul => l.checked_mul(r).map(zext),
BinOpKind::Div if r != 0 => l.checked_div(r).map(zext), BinOpKind::Div if r != 0 => l.checked_div(r).map(zext),
BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext), BinOpKind::Rem if r != 0 => l.checked_rem(r).map(zext),
BinOpKind::Shr => l.checked_shr( BinOpKind::Shr => l.checked_shr(r.try_into().expect("invalid shift")).map(zext),
r.try_into().expect("invalid shift") BinOpKind::Shl => l.checked_shl(r.try_into().expect("invalid shift")).map(zext),
).map(zext),
BinOpKind::Shl => l.checked_shl(
r.try_into().expect("invalid shift")
).map(zext),
BinOpKind::BitXor => Some(zext(l ^ r)), BinOpKind::BitXor => Some(zext(l ^ r)),
BinOpKind::BitOr => Some(zext(l | r)), BinOpKind::BitOr => Some(zext(l | r)),
BinOpKind::BitAnd => Some(zext(l & r)), BinOpKind::BitAnd => Some(zext(l & r)),
@ -360,20 +370,15 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
BinOpKind::Gt => Some(Constant::Bool(l > r)), BinOpKind::Gt => Some(Constant::Bool(l > r)),
_ => None, _ => None,
} }
} },
ty::Uint(_) => { ty::Uint(_) => match op.node {
match op.node {
BinOpKind::Add => l.checked_add(r).map(Constant::Int), BinOpKind::Add => l.checked_add(r).map(Constant::Int),
BinOpKind::Sub => l.checked_sub(r).map(Constant::Int), BinOpKind::Sub => l.checked_sub(r).map(Constant::Int),
BinOpKind::Mul => l.checked_mul(r).map(Constant::Int), BinOpKind::Mul => l.checked_mul(r).map(Constant::Int),
BinOpKind::Div => l.checked_div(r).map(Constant::Int), BinOpKind::Div => l.checked_div(r).map(Constant::Int),
BinOpKind::Rem => l.checked_rem(r).map(Constant::Int), BinOpKind::Rem => l.checked_rem(r).map(Constant::Int),
BinOpKind::Shr => l.checked_shr( BinOpKind::Shr => l.checked_shr(r.try_into().expect("shift too large")).map(Constant::Int),
r.try_into().expect("shift too large") BinOpKind::Shl => l.checked_shl(r.try_into().expect("shift too large")).map(Constant::Int),
).map(Constant::Int),
BinOpKind::Shl => l.checked_shl(
r.try_into().expect("shift too large")
).map(Constant::Int),
BinOpKind::BitXor => Some(Constant::Int(l ^ r)), BinOpKind::BitXor => Some(Constant::Int(l ^ r)),
BinOpKind::BitOr => Some(Constant::Int(l | r)), BinOpKind::BitOr => Some(Constant::Int(l | r)),
BinOpKind::BitAnd => Some(Constant::Int(l & r)), BinOpKind::BitAnd => Some(Constant::Int(l & r)),
@ -384,10 +389,8 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
BinOpKind::Ge => Some(Constant::Bool(l >= r)), BinOpKind::Ge => Some(Constant::Bool(l >= r)),
BinOpKind::Gt => Some(Constant::Bool(l > r)), BinOpKind::Gt => Some(Constant::Bool(l > r)),
_ => None, _ => None,
}
}, },
_ => None, _ => None,
}
}, },
(Constant::F32(l), Some(Constant::F32(r))) => match op.node { (Constant::F32(l), Some(Constant::F32(r))) => match op.node {
BinOpKind::Add => Some(Constant::F32(l + r)), BinOpKind::Add => Some(Constant::F32(l + r)),
@ -420,7 +423,9 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
(l, r) => match (op.node, l, r) { (l, r) => match (op.node, l, r) {
(BinOpKind::And, Constant::Bool(false), _) => Some(Constant::Bool(false)), (BinOpKind::And, Constant::Bool(false), _) => Some(Constant::Bool(false)),
(BinOpKind::Or, Constant::Bool(true), _) => Some(Constant::Bool(true)), (BinOpKind::Or, Constant::Bool(true), _) => Some(Constant::Bool(true)),
(BinOpKind::And, Constant::Bool(true), Some(r)) | (BinOpKind::Or, Constant::Bool(false), Some(r)) => Some(r), (BinOpKind::And, Constant::Bool(true), Some(r)) | (BinOpKind::Or, Constant::Bool(false), Some(r)) => {
Some(r)
},
(BinOpKind::BitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)), (BinOpKind::BitXor, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l ^ r)),
(BinOpKind::BitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)), (BinOpKind::BitAnd, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l & r)),
(BinOpKind::BitOr, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l | r)), (BinOpKind::BitOr, Constant::Bool(l), Some(Constant::Bool(r))) => Some(Constant::Bool(l | r)),
@ -431,36 +436,34 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
} }
pub fn miri_to_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result: &ty::Const<'tcx>) -> Option<Constant> { pub fn miri_to_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, result: &ty::Const<'tcx>) -> Option<Constant> {
use crate::rustc::mir::interpret::{Scalar, ConstValue}; use crate::rustc::mir::interpret::{ConstValue, Scalar};
match result.val { match result.val {
ConstValue::Scalar(Scalar::Bits{ bits: b, ..}) => match result.ty.sty { ConstValue::Scalar(Scalar::Bits { bits: b, .. }) => match result.ty.sty {
ty::Bool => Some(Constant::Bool(b == 1)), ty::Bool => Some(Constant::Bool(b == 1)),
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(b)), ty::Uint(_) | ty::Int(_) => Some(Constant::Int(b)),
ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits( ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
b.try_into().expect("invalid f32 bit representation") b.try_into().expect("invalid f32 bit representation"),
))), ))),
ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
b.try_into().expect("invalid f64 bit representation") b.try_into().expect("invalid f64 bit representation"),
))), ))),
// FIXME: implement other conversion // FIXME: implement other conversion
_ => None, _ => None,
}, },
ConstValue::ScalarPair(Scalar::Ptr(ptr), ConstValue::ScalarPair(Scalar::Ptr(ptr), Scalar::Bits { bits: n, .. }) => match result.ty.sty {
Scalar::Bits { bits: n, .. }) => match result.ty.sty {
ty::Ref(_, tam, _) => match tam.sty { ty::Ref(_, tam, _) => match tam.sty {
ty::Str => { ty::Str => {
let alloc = tcx let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
.alloc_map
.lock()
.unwrap_memory(ptr.alloc_id);
let offset = ptr.offset.bytes().try_into().expect("too-large pointer offset"); let offset = ptr.offset.bytes().try_into().expect("too-large pointer offset");
let n = n as usize; let n = n as usize;
String::from_utf8(alloc.bytes[offset..(offset + n)].to_owned()).ok().map(Constant::Str) String::from_utf8(alloc.bytes[offset..(offset + n)].to_owned())
.ok()
.map(Constant::Str)
}, },
_ => None, _ => None,
}, },
_ => None, _ => None,
} },
// FIXME: implement other conversions // FIXME: implement other conversions
_ => None, _ => None,
} }

View file

@ -7,18 +7,17 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty::Ty;
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::Ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::FxHashMap; use crate::rustc_data_structures::fx::FxHashMap;
use crate::syntax::symbol::LocalInternedString;
use crate::utils::{get_parent_expr, in_macro, snippet, span_lint_and_then, span_note_and_lint};
use crate::utils::{SpanlessEq, SpanlessHash};
use smallvec::SmallVec;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use std::hash::BuildHasherDefault; use std::hash::BuildHasherDefault;
use crate::syntax::symbol::LocalInternedString;
use smallvec::SmallVec;
use crate::utils::{SpanlessEq, SpanlessHash};
use crate::utils::{get_parent_expr, in_macro, snippet, span_lint_and_then, span_note_and_lint};
/// **What it does:** Checks for consecutive `if`s with the same condition. /// **What it does:** Checks for consecutive `if`s with the same condition.
/// ///
@ -168,7 +167,8 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) {
h.finish() h.finish()
}; };
let eq: &dyn Fn(&&Expr, &&Expr) -> bool = &|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) }; let eq: &dyn Fn(&&Expr, &&Expr) -> bool =
&|&lhs, &rhs| -> bool { SpanlessEq::new(cx).ignore_fn().eq_expr(lhs, rhs) };
if let Some((i, j)) = search_same(conds, hash, eq) { if let Some((i, j)) = search_same(conds, hash, eq) {
span_note_and_lint( span_note_and_lint(
@ -229,7 +229,10 @@ fn lint_match_arms(cx: &LateContext<'_, '_>, expr: &Expr) {
// hiding all the subsequent arms, and rust won't compile // hiding all the subsequent arms, and rust won't compile
db.span_note( db.span_note(
i.body.span, i.body.span,
&format!("`{}` has the same arm body as the `_` wildcard, consider removing it`", lhs), &format!(
"`{}` has the same arm body as the `_` wildcard, consider removing it`",
lhs
),
); );
} else { } else {
db.span_note(i.body.span, &format!("consider refactoring into `{} | {}`", lhs, rhs)); db.span_note(i.body.span, &format!("consider refactoring into `{} | {}`", lhs, rhs));
@ -276,11 +279,17 @@ fn if_sequence(mut expr: &Expr) -> (SmallVec<[&Expr; 1]>, SmallVec<[&Block; 1]>)
/// Return the list of bindings in a pattern. /// Return the list of bindings in a pattern.
fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<LocalInternedString, Ty<'tcx>> { fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<LocalInternedString, Ty<'tcx>> {
fn bindings_impl<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat, map: &mut FxHashMap<LocalInternedString, Ty<'tcx>>) { fn bindings_impl<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
pat: &Pat,
map: &mut FxHashMap<LocalInternedString, Ty<'tcx>>,
) {
match pat.node { match pat.node {
PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map), PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map),
PatKind::TupleStruct(_, ref pats, _) => for pat in pats { PatKind::TupleStruct(_, ref pats, _) => {
for pat in pats {
bindings_impl(cx, pat, map); bindings_impl(cx, pat, map);
}
}, },
PatKind::Binding(_, _, ident, ref as_pat) => { PatKind::Binding(_, _, ident, ref as_pat) => {
if let Entry::Vacant(v) = map.entry(ident.as_str()) { if let Entry::Vacant(v) = map.entry(ident.as_str()) {
@ -290,11 +299,15 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<LocalI
bindings_impl(cx, as_pat, map); bindings_impl(cx, as_pat, map);
} }
}, },
PatKind::Struct(_, ref fields, _) => for pat in fields { PatKind::Struct(_, ref fields, _) => {
for pat in fields {
bindings_impl(cx, &pat.node.pat, map); bindings_impl(cx, &pat.node.pat, map);
}
}, },
PatKind::Tuple(ref fields, _) => for pat in fields { PatKind::Tuple(ref fields, _) => {
for pat in fields {
bindings_impl(cx, pat, map); bindings_impl(cx, pat, map);
}
}, },
PatKind::Slice(ref lhs, ref mid, ref rhs) => { PatKind::Slice(ref lhs, ref mid, ref rhs) => {
for pat in lhs { for pat in lhs {
@ -316,7 +329,6 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<LocalI
result result
} }
fn search_same_sequenced<T, Eq>(exprs: &[T], eq: Eq) -> Option<(&T, &T)> fn search_same_sequenced<T, Eq>(exprs: &[T], eq: Eq) -> Option<(&T, &T)>
where where
Eq: Fn(&T, &T) -> bool, Eq: Fn(&T, &T) -> bool,
@ -345,10 +357,8 @@ where
}; };
} }
let mut map: FxHashMap<_, Vec<&_>> = FxHashMap::with_capacity_and_hasher( let mut map: FxHashMap<_, Vec<&_>> =
exprs.len(), FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
BuildHasherDefault::default()
);
for expr in exprs { for expr in exprs {
match map.entry(hash(expr)) { match map.entry(hash(expr)) {

View file

@ -7,11 +7,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::utils::{is_copy, match_path, paths, span_note_and_lint};
use crate::rustc::hir::{Item, ItemKind}; use crate::rustc::hir::{Item, ItemKind};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{is_copy, match_path, paths, span_note_and_lint};
/// **What it does:** Checks for types that implement `Copy` as well as /// **What it does:** Checks for types that implement `Copy` as well as
/// `Iterator`. /// `Iterator`.

View file

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! calculate cyclomatic complexity and warn about overly complex functions //! calculate cyclomatic complexity and warn about overly complex functions
use crate::rustc::cfg::CFG; use crate::rustc::cfg::CFG;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, LintContext};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::rustc::ty;
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::{Attribute, NodeId}; use crate::syntax::ast::{Attribute, NodeId};
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
@ -138,12 +137,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CyclomaticComplexity {
} }
fn enter_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) { fn enter_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) {
self.limit self.limit.push_attrs(cx.sess(), attrs, "cyclomatic_complexity");
.push_attrs(cx.sess(), attrs, "cyclomatic_complexity");
} }
fn exit_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) { fn exit_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) {
self.limit self.limit.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity");
.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity");
} }
} }
@ -197,7 +194,16 @@ impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> {
#[cfg(feature = "debugging")] #[cfg(feature = "debugging")]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn report_cc_bug(_: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span, _: NodeId) { fn report_cc_bug(
_: &LateContext<'_, '_>,
cc: u64,
narms: u64,
div: u64,
shorts: u64,
returns: u64,
span: Span,
_: NodeId,
) {
span_bug!( span_bug!(
span, span,
"Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \ "Clippy encountered a bug calculating cyclomatic complexity: cc = {}, arms = {}, \
@ -211,7 +217,16 @@ fn report_cc_bug(_: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts:
} }
#[cfg(not(feature = "debugging"))] #[cfg(not(feature = "debugging"))]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn report_cc_bug(cx: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts: u64, returns: u64, span: Span, id: NodeId) { fn report_cc_bug(
cx: &LateContext<'_, '_>,
cc: u64,
narms: u64,
div: u64,
shorts: u64,
returns: u64,
span: Span,
id: NodeId,
) {
if !is_allowed(cx, CYCLOMATIC_COMPLEXITY, id) { if !is_allowed(cx, CYCLOMATIC_COMPLEXITY, id) {
cx.sess().span_note_without_error( cx.sess().span_note_without_error(
span, span,
@ -220,11 +235,7 @@ fn report_cc_bug(cx: &LateContext<'_, '_>, cc: u64, narms: u64, div: u64, shorts
(hide this message with `#[allow(cyclomatic_complexity)]`): \ (hide this message with `#[allow(cyclomatic_complexity)]`): \
cc = {}, arms = {}, div = {}, shorts = {}, returns = {}. \ cc = {}, arms = {}, div = {}, shorts = {}, returns = {}. \
Please file a bug report.", Please file a bug report.",
cc, cc, narms, div, shorts, returns
narms,
div,
shorts,
returns
), ),
); );
} }

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::TyKind; use crate::rustc::ty::TyKind;
@ -17,7 +16,6 @@ use if_chain::if_chain;
use crate::utils::{any_parent_is_automatically_derived, match_def_path, opt_def_id, paths, span_lint_and_sugg}; use crate::utils::{any_parent_is_automatically_derived, match_def_path, opt_def_id, paths, span_lint_and_sugg};
/// **What it does:** Checks for literal calls to `Default::default()`. /// **What it does:** Checks for literal calls to `Default::default()`.
/// ///
/// **Why is this bad?** It's more clear to the reader to use the name of the type whose default is /// **Why is this bad?** It's more clear to the reader to use the name of the type whose default is

View file

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty::{self, Ty};
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::{self, Ty};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::paths; use crate::utils::paths;
use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_then}; use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_then};
use if_chain::if_chain;
/// **What it does:** Checks for deriving `Hash` but implementing `PartialEq` /// **What it does:** Checks for deriving `Hash` but implementing `PartialEq`
/// explicitly or vice versa. /// explicitly or vice versa.
@ -154,7 +153,8 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref
ty::Adt(def, _) if def.is_union() => return, ty::Adt(def, _) if def.is_union() => return,
// Some types are not Clone by default but could be cloned “by hand” if necessary // Some types are not Clone by default but could be cloned “by hand” if necessary
ty::Adt(def, substs) => for variant in &def.variants { ty::Adt(def, substs) => {
for variant in &def.variants {
for field in &variant.fields { for field in &variant.fields {
if let ty::FnDef(..) = field.ty(cx.tcx, substs).sty { if let ty::FnDef(..) = field.ty(cx.tcx, substs).sty {
return; return;
@ -167,6 +167,7 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref
} }
} }
} }
}
}, },
_ => (), _ => (),
} }

View file

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use itertools::Itertools;
use pulldown_cmark;
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast; use crate::syntax::ast;
use crate::syntax::source_map::{BytePos, Span}; use crate::syntax::source_map::{BytePos, Span};
use crate::syntax_pos::Pos; use crate::syntax_pos::Pos;
use crate::utils::span_lint; use crate::utils::span_lint;
use itertools::Itertools;
use pulldown_cmark;
use url::Url; use url::Url;
/// **What it does:** Checks for the presence of `_`, `::` or camel-case words /// **What it does:** Checks for the presence of `_`, `::` or camel-case words
@ -49,9 +48,7 @@ pub struct Doc {
impl Doc { impl Doc {
pub fn new(valid_idents: Vec<String>) -> Self { pub fn new(valid_idents: Vec<String>) -> Self {
Self { Self { valid_idents }
valid_idents,
}
} }
} }
@ -107,9 +104,7 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(
doc.push('\n'); doc.push('\n');
return ( return (
doc.to_owned(), doc.to_owned(),
vec![ vec![(doc.len(), span.with_lo(span.lo() + BytePos(prefix.len() as u32)))],
(doc.len(), span.with_lo(span.lo() + BytePos(prefix.len() as u32))),
],
); );
} }
} }
@ -275,13 +270,10 @@ fn check_word(cx: &EarlyContext<'_>, word: &str, span: Span) {
return false; return false;
} }
let s = if s.ends_with('s') { let s = if s.ends_with('s') { &s[..s.len() - 1] } else { s };
&s[..s.len() - 1]
} else {
s
};
s.chars().all(char::is_alphanumeric) && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 s.chars().all(char::is_alphanumeric)
&& s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1
&& s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0 && s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
} }

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! Lint on unnecessary double comparisons. Some examples: //! Lint on unnecessary double comparisons. Some examples:
use crate::rustc::hir::*; use crate::rustc::hir::*;
@ -51,18 +50,11 @@ impl LintPass for Pass {
impl<'a, 'tcx> Pass { impl<'a, 'tcx> Pass {
#[allow(clippy::similar_names)] #[allow(clippy::similar_names)]
fn check_binop( fn check_binop(&self, cx: &LateContext<'a, 'tcx>, op: BinOpKind, lhs: &'tcx Expr, rhs: &'tcx Expr, span: Span) {
&self,
cx: &LateContext<'a, 'tcx>,
op: BinOpKind,
lhs: &'tcx Expr,
rhs: &'tcx Expr,
span: Span,
) {
let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (lhs.node.clone(), rhs.node.clone()) { let (lkind, llhs, lrhs, rkind, rlhs, rrhs) = match (lhs.node.clone(), rhs.node.clone()) {
(ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => { (ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => {
(lb.node, llhs, lrhs, rb.node, rlhs, rrhs) (lb.node, llhs, lrhs, rb.node, rlhs, rrhs)
} },
_ => return, _ => return,
}; };
let mut spanless_eq = SpanlessEq::new(cx).ignore_fn(); let mut spanless_eq = SpanlessEq::new(cx).ignore_fn();
@ -84,13 +76,21 @@ impl<'a, 'tcx> Pass {
sugg, sugg,
applicability, applicability,
); );
}} }};
} }
match (op, lkind, rkind) { match (op, lkind, rkind) {
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => lint_double_comparison!(<=), (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => {
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => lint_double_comparison!(>=), lint_double_comparison!(<=)
(BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => lint_double_comparison!(!=), },
(BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => lint_double_comparison!(==), (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => {
lint_double_comparison!(>=)
},
(BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => {
lint_double_comparison!(!=)
},
(BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => {
lint_double_comparison!(==)
},
_ => (), _ => (),
}; };
} }

View file

@ -7,13 +7,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::syntax::ast::*;
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::*;
use crate::utils::{in_macro, span_lint}; use crate::utils::{in_macro, span_lint};
/// **What it does:** Checks for unnecessary double parentheses. /// **What it does:** Checks for unnecessary double parentheses.
/// ///
/// **Why is this bad?** This makes code harder to read and might indicate a /// **Why is this bad?** This makes code harder to read and might indicate a
@ -51,20 +49,39 @@ impl EarlyLintPass for DoubleParens {
match expr.node { match expr.node {
ExprKind::Paren(ref in_paren) => match in_paren.node { ExprKind::Paren(ref in_paren) => match in_paren.node {
ExprKind::Paren(_) | ExprKind::Tup(_) => { ExprKind::Paren(_) | ExprKind::Tup(_) => {
span_lint(cx, DOUBLE_PARENS, expr.span, "Consider removing unnecessary double parentheses"); span_lint(
cx,
DOUBLE_PARENS,
expr.span,
"Consider removing unnecessary double parentheses",
);
}, },
_ => {}, _ => {},
}, },
ExprKind::Call(_, ref params) => if params.len() == 1 { ExprKind::Call(_, ref params) => {
if params.len() == 1 {
let param = &params[0]; let param = &params[0];
if let ExprKind::Paren(_) = param.node { if let ExprKind::Paren(_) = param.node {
span_lint(cx, DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses"); span_lint(
cx,
DOUBLE_PARENS,
param.span,
"Consider removing unnecessary double parentheses",
);
}
} }
}, },
ExprKind::MethodCall(_, ref params) => if params.len() == 2 { ExprKind::MethodCall(_, ref params) => {
if params.len() == 2 {
let param = &params[1]; let param = &params[1];
if let ExprKind::Paren(_) = param.node { if let ExprKind::Paren(_) = param.node {
span_lint(cx, DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses"); span_lint(
cx,
DOUBLE_PARENS,
param.span,
"Consider removing unnecessary double parentheses",
);
}
} }
}, },
_ => {}, _ => {},

View file

@ -7,13 +7,12 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty;
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{is_copy, match_def_path, opt_def_id, paths, span_note_and_lint}; use crate::utils::{is_copy, match_def_path, opt_def_id, paths, span_note_and_lint};
use if_chain::if_chain;
/// **What it does:** Checks for calls to `std::mem::drop` with a reference /// **What it does:** Checks for calls to `std::mem::drop` with a reference
/// instead of an owned value. /// instead of an owned value.
@ -70,7 +69,7 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// let x:i32 = 42; // i32 implements Copy /// let x: i32 = 42; // i32 implements Copy
/// std::mem::drop(x) // A copy of x is passed to the function, leaving the /// std::mem::drop(x) // A copy of x is passed to the function, leaving the
/// // original unaffected /// // original unaffected
/// ``` /// ```
@ -97,7 +96,7 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// let x:i32 = 42; // i32 implements Copy /// let x: i32 = 42; // i32 implements Copy
/// std::mem::forget(x) // A copy of x is passed to the function, leaving the /// std::mem::forget(x) // A copy of x is passed to the function, leaving the
/// // original unaffected /// // original unaffected
/// ``` /// ```

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
@ -68,7 +67,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DurationSubsec {
expr.span, expr.span,
&format!("Calling `{}()` is more concise than this calculation", suggested_fn), &format!("Calling `{}()` is more concise than this calculation", suggested_fn),
"try", "try",
format!("{}.{}()", snippet_with_applicability(cx, args[0].span, "_", &mut applicability), suggested_fn), format!(
"{}.{}()",
snippet_with_applicability(cx, args[0].span, "_", &mut applicability),
suggested_fn
),
applicability, applicability,
); );
} }

View file

@ -7,10 +7,9 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! lint on if expressions with an else if, but without a final else branch //! lint on if expressions with an else if, but without a final else branch
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext}; use crate::rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::*; use crate::syntax::ast::*;

View file

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! lint when there is an enum with no variants //! lint when there is an enum with no variants
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::utils::span_lint_and_then; use crate::utils::span_lint_and_then;
/// **What it does:** Checks for `enum`s with no variants. /// **What it does:** Checks for `enum`s with no variants.
@ -47,11 +46,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EmptyEnum {
let did = cx.tcx.hir.local_def_id(item.id); let did = cx.tcx.hir.local_def_id(item.id);
if let ItemKind::Enum(..) = item.node { if let ItemKind::Enum(..) = item.node {
let ty = cx.tcx.type_of(did); let ty = cx.tcx.type_of(did);
let adt = ty.ty_adt_def() let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
.expect("already checked whether this is an enum");
if adt.variants.is_empty() { if adt.variants.is_empty() {
span_lint_and_then(cx, EMPTY_ENUM, item.span, "enum with no variants", |db| { span_lint_and_then(cx, EMPTY_ENUM, item.span, "enum with no variants", |db| {
db.span_help(item.span, "consider using the uninhabited type `!` or a wrapper around it"); db.span_help(
item.span,
"consider using the uninhabited type `!` or a wrapper around it",
);
}); });
} }
} }

View file

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain; use crate::rustc_errors::Applicability;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::SpanlessEq; use crate::utils::SpanlessEq;
use crate::utils::{get_item_name, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty}; use crate::utils::{get_item_name, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty};
use crate::rustc_errors::Applicability; use if_chain::if_chain;
/// **What it does:** Checks for uses of `contains_key` + `insert` on `HashMap` /// **What it does:** Checks for uses of `contains_key` + `insert` on `HashMap`
/// or `BTreeMap`. /// or `BTreeMap`.
@ -26,12 +25,16 @@ use crate::rustc_errors::Applicability;
/// **Known problems:** Some false negatives, eg.: /// **Known problems:** Some false negatives, eg.:
/// ```rust /// ```rust
/// let k = &key; /// let k = &key;
/// if !m.contains_key(k) { m.insert(k.clone(), v); } /// if !m.contains_key(k) {
/// m.insert(k.clone(), v);
/// }
/// ``` /// ```
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// if !m.contains_key(&k) { m.insert(k, v) } /// if !m.contains_key(&k) {
/// m.insert(k, v)
/// }
/// ``` /// ```
/// can be rewritten as: /// can be rewritten as:
/// ```rust /// ```rust
@ -60,7 +63,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapLint {
// in case of `if !m.contains_key(&k) { m.insert(k, v); }` // in case of `if !m.contains_key(&k) { m.insert(k, v); }`
// we can give a better error message // we can give a better error message
let sole_expr = { let sole_expr = {
else_block.is_none() && if let ExprKind::Block(ref then_block, _) = then_block.node { else_block.is_none()
&& if let ExprKind::Block(ref then_block, _) = then_block.node {
(then_block.expr.is_some() as usize) + then_block.stmts.len() == 1 (then_block.expr.is_some() as usize) + then_block.stmts.len() == 1
} else { } else {
true true

View file

@ -7,20 +7,19 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! lint on C-like enums that are `repr(isize/usize)` and have values that //! lint on C-like enums that are `repr(isize/usize)` and have values that
//! don't fit into an `i32` //! don't fit into an `i32`
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::consts::{miri_to_const, Constant};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::mir::interpret::GlobalId;
use crate::rustc::ty; use crate::rustc::ty;
use crate::rustc::ty::subst::Substs; use crate::rustc::ty::subst::Substs;
use crate::rustc::ty::util::IntTypeExt;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::{IntTy, UintTy}; use crate::syntax::ast::{IntTy, UintTy};
use crate::utils::span_lint; use crate::utils::span_lint;
use crate::consts::{Constant, miri_to_const};
use crate::rustc::ty::util::IntTypeExt;
use crate::rustc::mir::interpret::GlobalId;
/// **What it does:** Checks for C-like enumerations that are /// **What it does:** Checks for C-like enumerations that are
/// `repr(isize/usize)` and have values that don't fit into an `i32`. /// `repr(isize/usize)` and have values that don't fit into an `i32`.
@ -35,7 +34,7 @@ use crate::rustc::mir::interpret::GlobalId;
/// #[repr(usize)] /// #[repr(usize)]
/// enum NonPortable { /// enum NonPortable {
/// X = 0x1_0000_0000, /// X = 0x1_0000_0000,
/// Y = 0 /// Y = 0,
/// } /// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
@ -68,7 +67,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant {
let instance = ty::Instance::new(def_id, substs); let instance = ty::Instance::new(def_id, substs);
let c_id = GlobalId { let c_id = GlobalId {
instance, instance,
promoted: None promoted: None,
}; };
let constant = cx.tcx.const_eval(param_env.and(c_id)).ok(); let constant = cx.tcx.const_eval(param_env.and(c_id)).ok();
if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx.tcx, c)) { if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx.tcx, c)) {
@ -84,7 +83,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant {
if val <= i128::from(i32::max_value()) && val >= i128::from(i32::min_value()) { if val <= i128::from(i32::max_value()) && val >= i128::from(i32::min_value()) {
continue; continue;
} }
} },
ty::Uint(UintTy::Usize) if val > u128::from(u32::max_value()) => {}, ty::Uint(UintTy::Usize) if val > u128::from(u32::max_value()) => {},
_ => continue, _ => continue,
} }

View file

@ -7,11 +7,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! lint on `use`ing all variants of an enum //! lint on `use`ing all variants of an enum
use crate::rustc::hir::*;
use crate::rustc::hir::def::Def; use crate::rustc::hir::def::Def;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::NodeId; use crate::syntax::ast::NodeId;
@ -60,12 +59,7 @@ impl EnumGlobUse {
} }
if let ItemKind::Use(ref path, UseKind::Glob) = item.node { if let ItemKind::Use(ref path, UseKind::Glob) = item.node {
if let Def::Enum(_) = path.def { if let Def::Enum(_) = path.def {
span_lint( span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
cx,
ENUM_GLOB_USE,
item.span,
"don't use glob imports for enum variants",
);
} }
} }
} }

View file

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! lint on enum variants that are prefixed or suffixed by the same characters //! lint on enum variants that are prefixed or suffixed by the same characters
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, Lint}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, Lint, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::*; use crate::syntax::ast::*;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::syntax::symbol::LocalInternedString; use crate::syntax::symbol::LocalInternedString;
use crate::utils::{span_help_and_lint, span_lint};
use crate::utils::{camel_case, in_macro}; use crate::utils::{camel_case, in_macro};
use crate::utils::{span_help_and_lint, span_lint};
/// **What it does:** Detects enumeration variants that are prefixed or suffixed /// **What it does:** Detects enumeration variants that are prefixed or suffixed
/// by the same characters. /// by the same characters.
@ -139,10 +138,7 @@ fn var2str(var: &Variant) -> LocalInternedString {
fn partial_match(pre: &str, name: &str) -> usize { fn partial_match(pre: &str, name: &str) -> usize {
let mut name_iter = name.chars(); let mut name_iter = name.chars();
let _ = name_iter.next_back(); // make sure the name is never fully matched let _ = name_iter.next_back(); // make sure the name is never fully matched
pre.chars() pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count()
.zip(name_iter)
.take_while(|&(l, r)| l == r)
.count()
} }
/// Returns the number of chars that match from the end /// Returns the number of chars that match from the end
@ -171,9 +167,7 @@ fn check_variant(
for var in &def.variants { for var in &def.variants {
let name = var2str(var); let name = var2str(var);
if partial_match(item_name, &name) == item_name_chars if partial_match(item_name, &name) == item_name_chars
&& name.chars() && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
.nth(item_name_chars)
.map_or(false, |c| !c.is_lowercase())
{ {
span_lint(cx, lint, var.span, "Variant name starts with the enum's name"); span_lint(cx, lint, var.span, "Variant name starts with the enum's name");
} }
@ -277,19 +271,26 @@ impl EarlyLintPass for EnumVariantNames {
let rmatching = partial_rmatch(mod_camel, &item_camel); let rmatching = partial_rmatch(mod_camel, &item_camel);
let nchars = mod_camel.chars().count(); let nchars = mod_camel.chars().count();
let is_word_beginning = |c: char| { let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
c == '_' || c.is_uppercase() || c.is_numeric()
};
if matching == nchars { if matching == nchars {
match item_camel.chars().nth(nchars) { match item_camel.chars().nth(nchars) {
Some(c) if is_word_beginning(c) => Some(c) if is_word_beginning(c) => span_lint(
span_lint(cx, STUTTER, item.span, "item name starts with its containing module's name"), cx,
_ => () STUTTER,
item.span,
"item name starts with its containing module's name",
),
_ => (),
} }
} }
if rmatching == nchars { if rmatching == nchars {
span_lint(cx, STUTTER, item.span, "item name ends with its containing module's name"); span_lint(
cx,
STUTTER,
item.span,
"item name ends with its containing module's name",
);
} }
} }
} }

View file

@ -7,12 +7,13 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{in_macro, implements_trait, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq};
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::utils::{
implements_trait, in_macro, is_copy, multispan_sugg, snippet, span_lint, span_lint_and_then, SpanlessEq,
};
/// **What it does:** Checks for equal operands to comparison, logical and /// **What it does:** Checks for equal operands to comparison, logical and
/// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`, /// bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
@ -92,7 +93,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
BinOpKind::Shl => (cx.tcx.lang_items().shl_trait(), false), BinOpKind::Shl => (cx.tcx.lang_items().shl_trait(), false),
BinOpKind::Shr => (cx.tcx.lang_items().shr_trait(), false), BinOpKind::Shr => (cx.tcx.lang_items().shr_trait(), false),
BinOpKind::Ne | BinOpKind::Eq => (cx.tcx.lang_items().eq_trait(), true), BinOpKind::Ne | BinOpKind::Eq => (cx.tcx.lang_items().eq_trait(), true),
BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ge | BinOpKind::Gt => (cx.tcx.lang_items().ord_trait(), true), BinOpKind::Lt | BinOpKind::Le | BinOpKind::Ge | BinOpKind::Gt => {
(cx.tcx.lang_items().ord_trait(), true)
},
}; };
if let Some(trait_id) = trait_id { if let Some(trait_id) = trait_id {
#[allow(clippy::match_same_arms)] #[allow(clippy::match_same_arms)]
@ -122,7 +125,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
); );
}, },
) )
} else if lcpy && !rcpy && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()]) { } else if lcpy
&& !rcpy
&& implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()])
{
span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| { span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| {
let lsnip = snippet(cx, l.span, "...").to_string(); let lsnip = snippet(cx, l.span, "...").to_string();
db.span_suggestion_with_applicability( db.span_suggestion_with_applicability(
@ -132,7 +138,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
Applicability::MachineApplicable, // snippet Applicability::MachineApplicable, // snippet
); );
}) })
} else if !lcpy && rcpy && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()]) { } else if !lcpy
&& rcpy
&& implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()])
{
span_lint_and_then( span_lint_and_then(
cx, cx,
OP_REF, OP_REF,
@ -154,7 +163,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
(&ExprKind::AddrOf(_, ref l), _) => { (&ExprKind::AddrOf(_, ref l), _) => {
let lty = cx.tables.expr_ty(l); let lty = cx.tables.expr_ty(l);
let lcpy = is_copy(cx, lty); let lcpy = is_copy(cx, lty);
if (requires_ref || lcpy) && implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()]) { if (requires_ref || lcpy)
&& implements_trait(cx, lty, trait_id, &[cx.tables.expr_ty(right).into()])
{
span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| { span_lint_and_then(cx, OP_REF, e.span, "needlessly taken reference of left operand", |db| {
let lsnip = snippet(cx, l.span, "...").to_string(); let lsnip = snippet(cx, l.span, "...").to_string();
db.span_suggestion_with_applicability( db.span_suggestion_with_applicability(
@ -170,7 +181,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
(_, &ExprKind::AddrOf(_, ref r)) => { (_, &ExprKind::AddrOf(_, ref r)) => {
let rty = cx.tables.expr_ty(r); let rty = cx.tables.expr_ty(r);
let rcpy = is_copy(cx, rty); let rcpy = is_copy(cx, rty);
if (requires_ref || rcpy) && implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()]) { if (requires_ref || rcpy)
&& implements_trait(cx, cx.tables.expr_ty(left), trait_id, &[rty.into()])
{
span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |db| { span_lint_and_then(cx, OP_REF, e.span, "taken reference of right operand", |db| {
let rsnip = snippet(cx, r.span, "...").to_string(); let rsnip = snippet(cx, r.span, "...").to_string();
db.span_suggestion_with_applicability( db.span_suggestion_with_applicability(
@ -189,10 +202,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
} }
} }
fn is_valid_operator(op: BinOp) -> bool { fn is_valid_operator(op: BinOp) -> bool {
match op.node { match op.node {
BinOpKind::Sub | BinOpKind::Div | BinOpKind::Eq | BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge | BinOpKind::Ne | BinOpKind::And | BinOpKind::Or | BinOpKind::BitXor | BinOpKind::BitAnd | BinOpKind::BitOr => true, BinOpKind::Sub
| BinOpKind::Div
| BinOpKind::Eq
| BinOpKind::Lt
| BinOpKind::Le
| BinOpKind::Gt
| BinOpKind::Ge
| BinOpKind::Ne
| BinOpKind::And
| BinOpKind::Or
| BinOpKind::BitXor
| BinOpKind::BitAnd
| BinOpKind::BitOr => true,
_ => false, _ => false,
} }
} }

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::consts::{constant_simple, Constant}; use crate::consts::{constant_simple, Constant};
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
@ -25,7 +24,9 @@ use crate::utils::{in_macro, span_lint};
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// 0 / x; 0 * x; x & 0 /// 0 / x;
/// 0 * x;
/// x & 0
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub ERASING_OP, pub ERASING_OP,

View file

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit as visit; use crate::rustc::hir::intravisit as visit;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::middle::expr_use_visitor::*; use crate::rustc::middle::expr_use_visitor::*;
use crate::rustc::middle::mem_categorization::{cmt_, Categorization}; use crate::rustc::middle::mem_categorization::{cmt_, Categorization};
use crate::rustc::ty::{self, Ty};
use crate::rustc::ty::layout::LayoutOf; use crate::rustc::ty::layout::LayoutOf;
use crate::rustc::ty::{self, Ty};
use crate::rustc::util::nodemap::NodeSet; use crate::rustc::util::nodemap::NodeSet;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::NodeId; use crate::syntax::ast::NodeId;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::span_lint; use crate::utils::span_lint;
@ -65,7 +64,6 @@ impl LintPass for Pass {
} }
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_fn( fn check_fn(
&mut self, &mut self,
cx: &LateContext<'a, 'tcx>, cx: &LateContext<'a, 'tcx>,
@ -157,7 +155,15 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
} }
} }
} }
fn borrow(&mut self, _: NodeId, _: Span, cmt: &cmt_<'tcx>, _: ty::Region<'_>, _: ty::BorrowKind, loan_cause: LoanCause) { fn borrow(
&mut self,
_: NodeId,
_: Span,
cmt: &cmt_<'tcx>,
_: ty::Region<'_>,
_: ty::BorrowKind,
loan_cause: LoanCause,
) {
if let Categorization::Local(lid) = cmt.cat { if let Categorization::Local(lid) = cmt.cat {
match loan_cause { match loan_cause {
// x.foo() // x.foo()

View file

@ -7,17 +7,15 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty;
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then};
pub struct EtaPass; pub struct EtaPass;
/// **What it does:** Checks for closures which just call another function where /// **What it does:** Checks for closures which just call another function where
/// the function can be called directly. `unsafe` functions or calls where types /// the function can be called directly. `unsafe` functions or calls where types
/// get adjusted are ignored. /// get adjusted are ignored.
@ -52,8 +50,10 @@ impl LintPass for EtaPass {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
match expr.node { match expr.node {
ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => for arg in args { ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => {
for arg in args {
check_closure(cx, arg) check_closure(cx, arg)
}
}, },
_ => (), _ => (),
} }

View file

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::ty;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::syntax::ast; use crate::syntax::ast;
use crate::utils::{get_parent_expr, span_lint, span_note_and_lint}; use crate::utils::{get_parent_expr, span_lint, span_note_and_lint};
use if_chain::if_chain;
/// **What it does:** Checks for a read and a write to the same variable where /// **What it does:** Checks for a read and a write to the same variable where
/// whether the read occurs before or after the write depends on the evaluation /// whether the read occurs before or after the write depends on the evaluation
@ -30,7 +29,10 @@ use crate::utils::{get_parent_expr, span_lint, span_note_and_lint};
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// let mut x = 0; /// let mut x = 0;
/// let a = {x = 1; 1} + x; /// let a = {
/// x = 1;
/// 1
/// } + x;
/// // Unclear whether a is 1 or 2. /// // Unclear whether a is 1 or 2.
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
@ -74,7 +76,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
// Find a write to a local variable. // Find a write to a local variable.
match expr.node { match expr.node {
ExprKind::Assign(ref lhs, _) | ExprKind::AssignOp(_, ref lhs, _) => if let ExprKind::Path(ref qpath) = lhs.node { ExprKind::Assign(ref lhs, _) | ExprKind::AssignOp(_, ref lhs, _) => {
if let ExprKind::Path(ref qpath) = lhs.node {
if let QPath::Resolved(_, ref path) = *qpath { if let QPath::Resolved(_, ref path) = *qpath {
if path.segments.len() == 1 { if path.segments.len() == 1 {
if let def::Def::Local(var) = cx.tables.qpath_def(qpath, lhs.hir_id) { if let def::Def::Local(var) = cx.tables.qpath_def(qpath, lhs.hir_id) {
@ -88,6 +91,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence {
} }
} }
} }
}
}, },
_ => {}, _ => {},
} }
@ -95,13 +99,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence {
fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) { fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
match stmt.node { match stmt.node {
StmtKind::Expr(ref e, _) | StmtKind::Semi(ref e, _) => DivergenceVisitor { cx }.maybe_walk_expr(e), StmtKind::Expr(ref e, _) | StmtKind::Semi(ref e, _) => DivergenceVisitor { cx }.maybe_walk_expr(e),
StmtKind::Decl(ref d, _) => if let DeclKind::Local(ref local) = d.node { StmtKind::Decl(ref d, _) => {
if let Local { if let DeclKind::Local(ref local) = d.node {
init: Some(ref e), .. if let Local { init: Some(ref e), .. } = **local {
} = **local
{
DivergenceVisitor { cx }.visit_expr(e); DivergenceVisitor { cx }.visit_expr(e);
} }
}
}, },
} }
} }
@ -179,12 +182,12 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
/// This means reads for which there is a common ancestor between the read and /// This means reads for which there is a common ancestor between the read and
/// the write such that /// the write such that
/// ///
/// * evaluating the ancestor necessarily evaluates both the read and the write /// * evaluating the ancestor necessarily evaluates both the read and the write (for example, `&x`
/// (for example, `&x` and `|| x = 1` don't necessarily evaluate `x`), and /// and `|| x = 1` don't necessarily evaluate `x`), and
/// ///
/// * which one is evaluated first depends on the order of sub-expression /// * which one is evaluated first depends on the order of sub-expression evaluation. Blocks, `if`s,
/// evaluation. Blocks, `if`s, loops, `match`es, and the short-circuiting /// loops, `match`es, and the short-circuiting logical operators are considered to have a defined
/// logical operators are considered to have a defined evaluation order. /// evaluation order.
/// ///
/// When such a read is found, the lint is triggered. /// When such a read is found, the lint is triggered.
fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) { fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
@ -232,14 +235,14 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> St
} }
match expr.node { match expr.node {
ExprKind::Array(_) | ExprKind::Array(_)
ExprKind::Tup(_) | | ExprKind::Tup(_)
ExprKind::MethodCall(..) | | ExprKind::MethodCall(..)
ExprKind::Call(_, _) | | ExprKind::Call(_, _)
ExprKind::Assign(_, _) | | ExprKind::Assign(_, _)
ExprKind::Index(_, _) | | ExprKind::Index(_, _)
ExprKind::Repeat(_, _) | | ExprKind::Repeat(_, _)
ExprKind::Struct(_, _, _) => { | ExprKind::Struct(_, _, _) => {
walk_expr(vis, expr); walk_expr(vis, expr);
}, },
ExprKind::Binary(op, _, _) | ExprKind::AssignOp(op, _, _) => { ExprKind::Binary(op, _, _) | ExprKind::AssignOp(op, _, _) => {
@ -253,13 +256,12 @@ fn check_expr<'a, 'tcx>(vis: &mut ReadVisitor<'a, 'tcx>, expr: &'tcx Expr) -> St
ExprKind::Closure(_, _, _, _, _) => { ExprKind::Closure(_, _, _, _, _) => {
// Either // Either
// //
// * `var` is defined in the closure body, in which case we've // * `var` is defined in the closure body, in which case we've reached the top of the enclosing
// reached the top of the enclosing function and can stop, or // function and can stop, or
// //
// * `var` is captured by the closure, in which case, because // * `var` is captured by the closure, in which case, because evaluating a closure does not evaluate
// evaluating a closure does not evaluate its body, we don't // its body, we don't necessarily have a write, so we need to stop to avoid generating false
// necessarily have a write, so we need to stop to avoid // positives.
// generating false positives.
// //
// This is also the only place we need to stop early (grrr). // This is also the only place we need to stop early (grrr).
return StopEarly::Stop; return StopEarly::Stop;

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::TyKind; use crate::rustc::ty::TyKind;
@ -82,7 +81,7 @@ impl ExcessivePrecision {
let max = max_digits(fty); let max = max_digits(fty);
let sym_str = sym.as_str(); let sym_str = sym.as_str();
if dot_zero_exclusion(&sym_str) { if dot_zero_exclusion(&sym_str) {
return None return None;
} }
// Try to bail out if the float is for sure fine. // Try to bail out if the float is for sure fine.
// If its within the 2 decimal digits of being out of precision we // If its within the 2 decimal digits of being out of precision we
@ -116,9 +115,7 @@ impl ExcessivePrecision {
/// Ex 1_000_000_000. /// Ex 1_000_000_000.
fn dot_zero_exclusion(s: &str) -> bool { fn dot_zero_exclusion(s: &str) -> bool {
if let Some(after_dec) = s.split('.').nth(1) { if let Some(after_dec) = s.split('.').nth(1) {
let mut decpart = after_dec let mut decpart = after_dec.chars().take_while(|c| *c != 'e' || *c != 'E');
.chars()
.take_while(|c| *c != 'e' || *c != 'E');
match decpart.next() { match decpart.next() {
Some('0') => decpart.count() == 0, Some('0') => decpart.count() == 0,
@ -169,7 +166,9 @@ impl FloatFormat {
.unwrap_or(FloatFormat::Normal) .unwrap_or(FloatFormat::Normal)
} }
fn format<T>(&self, f: T) -> String fn format<T>(&self, f: T) -> String
where T: fmt::UpperExp + fmt::LowerExp + fmt::Display { where
T: fmt::UpperExp + fmt::LowerExp + fmt::Display,
{
match self { match self {
FloatFormat::LowerExp => format!("{:e}", f), FloatFormat::LowerExp => format!("{:e}", f),
FloatFormat::UpperExp => format!("{:E}", f), FloatFormat::UpperExp => format!("{:E}", f),

View file

@ -7,13 +7,12 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::utils::{is_expn_of, match_def_path, resolve_node, span_lint};
use crate::utils::opt_def_id; use crate::utils::opt_def_id;
use crate::utils::{is_expn_of, match_def_path, resolve_node, span_lint};
use if_chain::if_chain;
/// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be /// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be
/// replaced with `(e)print!()` / `(e)println!()` /// replaced with `(e)print!()` / `(e)println!()`
@ -30,8 +29,7 @@ use crate::utils::opt_def_id;
declare_clippy_lint! { declare_clippy_lint! {
pub EXPLICIT_WRITE, pub EXPLICIT_WRITE,
complexity, complexity,
"using the `write!()` family of functions instead of the `print!()` family \ "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work"
of functions, when using the latter would work"
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]

View file

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty; use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax_pos::Span; use crate::syntax_pos::Span;
use crate::utils::{match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty, is_expn_of, opt_def_id};
use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT}; use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT};
use crate::utils::{is_expn_of, match_def_path, method_chain_args, opt_def_id, span_lint_and_then, walk_ptrs_ty};
use if_chain::if_chain;
/// **What it does:** Checks for impls of `From<..>` that contain `panic!()` or `unwrap()` /// **What it does:** Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`
/// ///
@ -62,8 +61,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FallibleImplFrom {
} }
fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_items: &hir::HirVec<hir::ImplItemRef>) { fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_items: &hir::HirVec<hir::ImplItemRef>) {
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use crate::rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use crate::rustc::hir::*;
struct FindPanicUnwrap<'a, 'tcx: 'a> { struct FindPanicUnwrap<'a, 'tcx: 'a> {
tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,

View file

@ -7,16 +7,18 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty; use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::LitKind; use crate::syntax::ast::LitKind;
use crate::utils::paths; use crate::utils::paths;
use crate::utils::{in_macro, is_expn_of, last_path_segment, match_def_path, match_type, opt_def_id, resolve_node, snippet, span_lint_and_then, walk_ptrs_ty}; use crate::utils::{
use crate::rustc_errors::Applicability; in_macro, is_expn_of, last_path_segment, match_def_path, match_type, opt_def_id, resolve_node, snippet,
span_lint_and_then, walk_ptrs_ty,
};
use if_chain::if_chain;
/// **What it does:** Checks for the use of `format!("string literal with no /// **What it does:** Checks for the use of `format!("string literal with no
/// argument")` and `format!("{}", foo)` where `foo` is a string. /// argument")` and `format!("{}", foo)` where `foo` is a string.
@ -92,7 +94,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} }
}, },
// `format!("foo")` expansion contains `match () { () => [], }` // `format!("foo")` expansion contains `match () { () => [], }`
ExprKind::Match(ref matchee, _, _) => if let ExprKind::Tup(ref tup) = matchee.node { ExprKind::Match(ref matchee, _, _) => {
if let ExprKind::Tup(ref tup) = matchee.node {
if tup.is_empty() { if tup.is_empty() {
let sugg = format!("{}.to_string()", snippet(cx, expr.span, "<expr>").into_owned()); let sugg = format!("{}.to_string()", snippet(cx, expr.span, "<expr>").into_owned());
span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| { span_lint_and_then(cx, USELESS_FORMAT, span, "useless use of `format!`", |db| {
@ -104,6 +107,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
); );
}); });
} }
}
}, },
_ => (), _ => (),
} }

View file

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast; use crate::syntax::ast;
use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
use crate::syntax::ptr::P; use crate::syntax::ptr::P;
use crate::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
/// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-` /// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
/// operators. /// operators.
@ -78,7 +77,6 @@ declare_clippy_lint! {
"possible missing comma in array" "possible missing comma in array"
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Formatting; pub struct Formatting;
@ -96,8 +94,8 @@ impl EarlyLintPass for Formatting {
fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
for w in block.stmts.windows(2) { for w in block.stmts.windows(2) {
match (&w[0].node, &w[1].node) { match (&w[0].node, &w[1].node) {
(&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second)) | (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Expr(ref second))
(&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => { | (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref second)) => {
check_consecutive_ifs(cx, first, second); check_consecutive_ifs(cx, first, second);
}, },
_ => (), _ => (),
@ -153,9 +151,7 @@ fn check_else_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
// the snippet should look like " else \n " with maybe comments anywhere // the snippet should look like " else \n " with maybe comments anywhere
// its bad when there is a \n after the “else” // its bad when there is a \n after the “else”
if let Some(else_snippet) = snippet_opt(cx, else_span) { if let Some(else_snippet) = snippet_opt(cx, else_span) {
let else_pos = else_snippet let else_pos = else_snippet.find("else").expect("there must be a `else` here");
.find("else")
.expect("there must be a `else` here");
if else_snippet[else_pos..].contains('\n') { if else_snippet[else_pos..].contains('\n') {
span_note_and_lint( span_note_and_lint(
@ -175,9 +171,7 @@ fn check_else_if(cx: &EarlyContext<'_>, expr: &ast::Expr) {
fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool { fn has_unary_equivalent(bin_op: ast::BinOpKind) -> bool {
// &, *, - // &, *, -
bin_op == ast::BinOpKind::And bin_op == ast::BinOpKind::And || bin_op == ast::BinOpKind::Mul || bin_op == ast::BinOpKind::Sub
|| bin_op == ast::BinOpKind::Mul
|| bin_op == ast::BinOpKind::Sub
} }
/// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array /// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
@ -208,7 +202,9 @@ fn check_array(cx: &EarlyContext<'_>, expr: &ast::Expr) {
/// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs. /// Implementation of the `SUSPICIOUS_ELSE_FORMATTING` lint for consecutive ifs.
fn check_consecutive_ifs(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) { fn check_consecutive_ifs(cx: &EarlyContext<'_>, first: &ast::Expr, second: &ast::Expr) {
if !differing_macro_contexts(first.span, second.span) && !in_macro(first.span) && unsugar_if(first).is_some() if !differing_macro_contexts(first.span, second.span)
&& !in_macro(first.span)
&& unsugar_if(first).is_some()
&& unsugar_if(second).is_some() && unsugar_if(second).is_some()
{ {
// where the else would be // where the else would be

View file

@ -7,19 +7,18 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use matches::matches;
use crate::rustc::hir::intravisit;
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty;
use crate::rustc::hir::def::Def; use crate::rustc::hir::def::Def;
use crate::rustc::hir::intravisit;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::FxHashSet; use crate::rustc_data_structures::fx::FxHashSet;
use crate::syntax::ast;
use crate::rustc_target::spec::abi::Abi; use crate::rustc_target::spec::abi::Abi;
use crate::syntax::ast;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::{iter_input_pats, span_lint, type_is_unsafe_function}; use crate::utils::{iter_input_pats, span_lint, type_is_unsafe_function};
use matches::matches;
/// **What it does:** Checks for functions with too many parameters. /// **What it does:** Checks for functions with too many parameters.
/// ///
@ -31,8 +30,9 @@ use crate::utils::{iter_input_pats, span_lint, type_is_unsafe_function};
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: /// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
/// f32) { .. } /// ..
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub TOO_MANY_ARGUMENTS, pub TOO_MANY_ARGUMENTS,
@ -58,7 +58,9 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// pub fn foo(x: *const u8) { println!("{}", unsafe { *x }); } /// pub fn foo(x: *const u8) {
/// println!("{}", unsafe { *x });
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub NOT_UNSAFE_PTR_ARG_DEREF, pub NOT_UNSAFE_PTR_ARG_DEREF,
@ -73,9 +75,7 @@ pub struct Functions {
impl Functions { impl Functions {
pub fn new(threshold: u64) -> Self { pub fn new(threshold: u64) -> Self {
Self { Self { threshold }
threshold,
}
} }
} }
@ -111,8 +111,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
if !is_impl { if !is_impl {
// don't lint extern functions decls, it's not their fault either // don't lint extern functions decls, it's not their fault either
match kind { match kind {
hir::intravisit::FnKind::Method(_, &hir::MethodSig { header: hir::FnHeader { abi: Abi::Rust, .. }, .. }, _, _) | hir::intravisit::FnKind::Method(
hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => self.check_arg_number(cx, decl, span), _,
&hir::MethodSig {
header: hir::FnHeader { abi: Abi::Rust, .. },
..
},
_,
_,
)
| hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => {
self.check_arg_number(cx, decl, span)
},
_ => {}, _ => {},
} }
} }

View file

@ -7,14 +7,15 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::syntax::ast::NodeId;
use crate::utils::{in_macro, match_def_path, match_trait_method, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_then};
use crate::utils::{opt_def_id, paths, resolve_node};
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::syntax::ast::NodeId;
use crate::utils::{
in_macro, match_def_path, match_trait_method, same_tys, snippet, snippet_with_macro_callsite, span_lint_and_then,
};
use crate::utils::{opt_def_id, paths, resolve_node};
/// **What it does:** Checks for always-identical `Into`/`From`/`IntoIter` conversions. /// **What it does:** Checks for always-identical `Into`/`From`/`IntoIter` conversions.
/// ///
@ -101,14 +102,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion {
} }
}, },
ExprKind::Call(ref path, ref args) => if let ExprKind::Path(ref qpath) = path.node { ExprKind::Call(ref path, ref args) => {
if let ExprKind::Path(ref qpath) = path.node {
if let Some(def_id) = opt_def_id(resolve_node(cx, qpath, path.hir_id)) { if let Some(def_id) = opt_def_id(resolve_node(cx, qpath, path.hir_id)) {
if match_def_path(cx.tcx, def_id, &paths::FROM_FROM[..]) { if match_def_path(cx.tcx, def_id, &paths::FROM_FROM[..]) {
let a = cx.tables.expr_ty(e); let a = cx.tables.expr_ty(e);
let b = cx.tables.expr_ty(&args[0]); let b = cx.tables.expr_ty(&args[0]);
if same_tys(cx, a, b) { if same_tys(cx, a, b) {
let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned(); let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned();
let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); let sugg_msg =
format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| { span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| {
db.span_suggestion_with_applicability( db.span_suggestion_with_applicability(
e.span, e.span,
@ -120,6 +123,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion {
} }
} }
} }
}
}, },
_ => {}, _ => {},

View file

@ -7,14 +7,13 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::consts::{constant_simple, Constant}; use crate::consts::{constant_simple, Constant};
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::{in_macro, snippet, span_lint, unsext, clip}; use crate::utils::{clip, in_macro, snippet, span_lint, unsext};
use crate::rustc::ty;
/// **What it does:** Checks for identity operations, e.g. `x + 0`. /// **What it does:** Checks for identity operations, e.g. `x + 0`.
/// ///

View file

@ -7,11 +7,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! lint on if branches that could be swapped so no `!` operation is necessary //! lint on if branches that could be swapped so no `!` operation is necessary
//! on the condition //! on the condition
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, in_external_macro, LintContext}; use crate::rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::*; use crate::syntax::ast::*;

View file

@ -7,18 +7,17 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! lint on indexing and slicing operations //! lint on indexing and slicing operations
use crate::consts::{constant, Constant}; use crate::consts::{constant, Constant};
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::RangeLimits;
use crate::utils; use crate::utils;
use crate::utils::higher; use crate::utils::higher;
use crate::utils::higher::Range; use crate::utils::higher::Range;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty;
use crate::syntax::ast::RangeLimits;
/// **What it does:** Checks for out of bounds array indexing with a constant /// **What it does:** Checks for out of bounds array indexing with a constant
/// index. /// index.
@ -29,7 +28,7 @@ use crate::syntax::ast::RangeLimits;
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// let x = [1,2,3,4]; /// let x = [1, 2, 3, 4];
/// ///
/// // Bad /// // Bad
/// x[9]; /// x[9];
@ -108,7 +107,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
if let ExprKind::Index(ref array, ref index) = &expr.node { if let ExprKind::Index(ref array, ref index) = &expr.node {
let ty = cx.tables.expr_ty(array); let ty = cx.tables.expr_ty(array);
if let Some(range) = higher::range(cx, index) { if let Some(range) = higher::range(cx, index) {
// Ranged indexes, i.e. &x[n..m], &x[n..], &x[..n] and &x[..] // Ranged indexes, i.e. &x[n..m], &x[n..], &x[..n] and &x[..]
if let ty::Array(_, s) = ty.sty { if let ty::Array(_, s) = ty.sty {
let size: u128 = s.assert_usize(cx.tcx).unwrap().into(); let size: u128 = s.assert_usize(cx.tcx).unwrap().into();
@ -153,13 +151,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
(None, None) => return, // [..] is ok. (None, None) => return, // [..] is ok.
}; };
utils::span_help_and_lint( utils::span_help_and_lint(cx, INDEXING_SLICING, expr.span, "slicing may panic.", help_msg);
cx,
INDEXING_SLICING,
expr.span,
"slicing may panic.",
help_msg,
);
} else { } else {
// Catchall non-range index, i.e. [n] or [n << m] // Catchall non-range index, i.e. [n] or [n << m]
if let ty::Array(..) = ty.sty { if let ty::Array(..) = ty.sty {
@ -189,23 +181,21 @@ fn to_const_range<'a, 'tcx>(
range: Range<'_>, range: Range<'_>,
array_size: u128, array_size: u128,
) -> (Option<u128>, Option<u128>) { ) -> (Option<u128>, Option<u128>) {
let s = range let s = range.start.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
.start
.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
let start = match s { let start = match s {
Some(Some(Constant::Int(x))) => Some(x), Some(Some(Constant::Int(x))) => Some(x),
Some(_) => None, Some(_) => None,
None => Some(0), None => Some(0),
}; };
let e = range let e = range.end.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
.end
.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
let end = match e { let end = match e {
Some(Some(Constant::Int(x))) => if range.limits == RangeLimits::Closed { Some(Some(Constant::Int(x))) => {
if range.limits == RangeLimits::Closed {
Some(x + 1) Some(x + 1)
} else { } else {
Some(x) Some(x)
}
}, },
Some(_) => None, Some(_) => None,
None => Some(array_size), None => Some(array_size),

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use super::utils::{get_arg_name, match_var, remove_blocks, snippet_with_applicability, span_lint_and_sugg}; use super::utils::{get_arg_name, match_var, remove_blocks, snippet_with_applicability, span_lint_and_sugg};
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
@ -160,7 +159,8 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
First => is_infinite(cx, &args[0]), First => is_infinite(cx, &args[0]),
Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])), Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])),
All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])), All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])),
}).and(cap); })
.and(cap);
} }
} }
if method.ident.name == "flat_map" && args.len() == 2 { if method.ident.name == "flat_map" && args.len() == 2 {
@ -173,14 +173,14 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
}, },
ExprKind::Block(ref block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)), ExprKind::Block(ref block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)),
ExprKind::Box(ref e) | ExprKind::AddrOf(_, ref e) => is_infinite(cx, e), ExprKind::Box(ref e) | ExprKind::AddrOf(_, ref e) => is_infinite(cx, e),
ExprKind::Call(ref path, _) => if let ExprKind::Path(ref qpath) = path.node { ExprKind::Call(ref path, _) => {
if let ExprKind::Path(ref qpath) = path.node {
match_qpath(qpath, &paths::REPEAT).into() match_qpath(qpath, &paths::REPEAT).into()
} else { } else {
Finite Finite
}
}, },
ExprKind::Struct(..) => higher::range(cx, expr) ExprKind::Struct(..) => higher::range(cx, expr).map_or(false, |r| r.end.is_none()).into(),
.map_or(false, |r| r.end.is_none())
.into(),
_ => Finite, _ => Finite,
} }
} }
@ -235,10 +235,10 @@ fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
} }
} }
}, },
ExprKind::Binary(op, ref l, ref r) => if op.node.is_comparison() { ExprKind::Binary(op, ref l, ref r) => {
return is_infinite(cx, l) if op.node.is_comparison() {
.and(is_infinite(cx, r)) return is_infinite(cx, l).and(is_infinite(cx, r)).and(MaybeInfinite);
.and(MaybeInfinite); }
}, // TODO: ExprKind::Loop + Match }, // TODO: ExprKind::Loop + Match
_ => (), _ => (),
} }

View file

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! lint on inherent implementations //! lint on inherent implementations
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::FxHashMap; use crate::rustc_data_structures::fx::FxHashMap;
use std::default::Default;
use crate::syntax_pos::Span; use crate::syntax_pos::Span;
use crate::utils::span_lint_and_then; use crate::utils::span_lint_and_then;
use std::default::Default;
/// **What it does:** Checks for multiple inherent implementations of a struct /// **What it does:** Checks for multiple inherent implementations of a struct
/// ///
@ -56,7 +55,9 @@ pub struct Pass {
impl Default for Pass { impl Default for Pass {
fn default() -> Self { fn default() -> Self {
Self { impls: FxHashMap::default() } Self {
impls: FxHashMap::default(),
}
} }
} }
@ -88,11 +89,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
let mut impl_spans = impls let mut impl_spans = impls
.iter() .iter()
.filter_map(|impl_def| self.impls.get(impl_def)) .filter_map(|impl_def| self.impls.get(impl_def))
.filter_map(|(span, generics)| if generics.params.len() == 0 { .filter_map(|(span, generics)| if generics.params.len() == 0 { Some(span) } else { None });
Some(span)
} else {
None
});
if let Some(initial_span) = impl_spans.nth(0) { if let Some(initial_span) = impl_spans.nth(0) {
impl_spans.for_each(|additional_span| { impl_spans.for_each(|additional_span| {
span_lint_and_then( span_lint_and_then(
@ -101,10 +98,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
*additional_span, *additional_span,
"Multiple implementations of this structure", "Multiple implementations of this structure",
|db| { |db| {
db.span_note( db.span_note(*initial_span, "First implementation here");
*initial_span,
"First implementation here",
);
}, },
) )
}) })

View file

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! checks for `#[inline]` on trait methods without bodies //! checks for `#[inline]` on trait methods without bodies
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*; use crate::rustc_errors::Applicability;
use crate::syntax::ast::{Attribute, Name}; use crate::syntax::ast::{Attribute, Name};
use crate::utils::span_lint_and_then; use crate::utils::span_lint_and_then;
use crate::utils::sugg::DiagnosticBuilderExt; use crate::utils::sugg::DiagnosticBuilderExt;
use crate::rustc_errors::Applicability;
/// **What it does:** Checks for `#[inline]` on trait methods without bodies /// **What it does:** Checks for `#[inline]` on trait methods without bodies
/// ///

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! lint on blocks unnecessarily using >= with a + 1 or - 1 //! lint on blocks unnecessarily using >= with a + 1 or - 1
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
@ -162,14 +161,20 @@ impl IntPlusOne {
} }
fn emit_warning(&self, cx: &EarlyContext<'_>, block: &Expr, recommendation: String) { fn emit_warning(&self, cx: &EarlyContext<'_>, block: &Expr, recommendation: String) {
span_lint_and_then(cx, INT_PLUS_ONE, block.span, "Unnecessary `>= y + 1` or `x - 1 >=`", |db| { span_lint_and_then(
cx,
INT_PLUS_ONE,
block.span,
"Unnecessary `>= y + 1` or `x - 1 >=`",
|db| {
db.span_suggestion_with_applicability( db.span_suggestion_with_applicability(
block.span, block.span,
"change `>= y + 1` to `> y` as shown", "change `>= y + 1` to `> y` as shown",
recommendation, recommendation,
Applicability::MachineApplicable, // snippet Applicability::MachineApplicable, // snippet
); );
}); },
);
} }
} }

View file

@ -7,13 +7,12 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty;
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{match_def_path, opt_def_id, paths, span_help_and_lint}; use crate::utils::{match_def_path, opt_def_id, paths, span_help_and_lint};
use if_chain::if_chain;
/// **What it does:** Checks for creation of references to zeroed or uninitialized memory. /// **What it does:** Checks for creation of references to zeroed or uninitialized memory.
/// ///

View file

@ -7,14 +7,13 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! lint when items are used after statements //! lint when items are used after statements
use matches::matches;
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast::*; use crate::syntax::ast::*;
use crate::utils::{in_macro, span_lint}; use crate::utils::{in_macro, span_lint};
use matches::matches;
/// **What it does:** Checks for items declared after some statement in a block. /// **What it does:** Checks for items declared after some statement in a block.
/// ///
@ -59,7 +58,8 @@ impl EarlyLintPass for ItemsAfterStatements {
} }
// skip initial items // skip initial items
let stmts = item.stmts let stmts = item
.stmts
.iter() .iter()
.map(|stmt| &stmt.node) .map(|stmt| &stmt.node)
.skip_while(|s| matches!(**s, StmtKind::Item(..))); .skip_while(|s| matches!(**s, StmtKind::Item(..)));

View file

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! lint when there is a large size difference between variants on an enum //! lint when there is a large size difference between variants on an enum
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::utils::{snippet_opt, span_lint_and_then}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::layout::LayoutOf; use crate::rustc::ty::layout::LayoutOf;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::utils::{snippet_opt, span_lint_and_then};
/// **What it does:** Checks for large size differences between variants on /// **What it does:** Checks for large size differences between variants on
/// `enum`s. /// `enum`s.
@ -63,8 +62,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant {
let did = cx.tcx.hir.local_def_id(item.id); let did = cx.tcx.hir.local_def_id(item.id);
if let ItemKind::Enum(ref def, _) = item.node { if let ItemKind::Enum(ref def, _) = item.node {
let ty = cx.tcx.type_of(did); let ty = cx.tcx.type_of(did);
let adt = ty.ty_adt_def() let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
.expect("already checked whether this is an enum");
let mut smallest_variant: Option<(_, _)> = None; let mut smallest_variant: Option<(_, _)> = None;
let mut largest_variant: Option<(_, _)> = None; let mut largest_variant: Option<(_, _)> = None;

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::def_id::DefId; use crate::rustc::hir::def_id::DefId;
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
@ -32,18 +31,26 @@ use crate::utils::{get_item_name, in_macro, snippet_with_applicability, span_lin
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// if x.len() == 0 { .. } /// if x.len() == 0 {
/// if y.len() != 0 { .. } /// ..
/// }
/// if y.len() != 0 {
/// ..
/// }
/// ``` /// ```
/// instead use /// instead use
/// ```rust /// ```rust
/// if x.len().is_empty() { .. } /// if x.len().is_empty() {
/// if !y.len().is_empty() { .. } /// ..
/// }
/// if !y.len().is_empty() {
/// ..
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub LEN_ZERO, pub LEN_ZERO,
style, style,
"checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \ "checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \
could be used instead" could be used instead"
} }
@ -61,7 +68,9 @@ declare_clippy_lint! {
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// impl X { /// impl X {
/// pub fn len(&self) -> usize { .. } /// pub fn len(&self) -> usize {
/// ..
/// }
/// } /// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
@ -125,7 +134,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero {
fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items: &[TraitItemRef]) { fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items: &[TraitItemRef]) {
fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: &str) -> bool { fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: &str) -> bool {
item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind { item.ident.name == name
&& if let AssociatedItemKind::Method { has_self } = item.kind {
has_self && { has_self && {
let did = cx.tcx.hir.local_def_id(item.id.node_id); let did = cx.tcx.hir.local_def_id(item.id.node_id);
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1 cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
@ -153,7 +163,9 @@ fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items
.iter() .iter()
.flat_map(|&i| cx.tcx.associated_items(i)) .flat_map(|&i| cx.tcx.associated_items(i))
.any(|i| { .any(|i| {
i.kind == ty::AssociatedKind::Method && i.method_has_self_argument && i.ident.name == "is_empty" i.kind == ty::AssociatedKind::Method
&& i.method_has_self_argument
&& i.ident.name == "is_empty"
&& cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1 && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
}); });
@ -173,7 +185,8 @@ fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items
fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item, impl_items: &[ImplItemRef]) { fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item, impl_items: &[ImplItemRef]) {
fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bool { fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bool {
item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind { item.ident.name == name
&& if let AssociatedItemKind::Method { has_self } = item.kind {
has_self && { has_self && {
let did = cx.tcx.hir.local_def_id(item.id.node_id); let did = cx.tcx.hir.local_def_id(item.id.node_id);
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1 cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
@ -251,7 +264,11 @@ fn check_len(
span, span,
&format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }), &format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
"using `is_empty` is clearer and more explicit", "using `is_empty` is clearer and more explicit",
format!("{}{}.is_empty()", op, snippet_with_applicability(cx, args[0].span, "_", &mut applicability)), format!(
"{}{}.is_empty()",
op,
snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
),
applicability, applicability,
); );
} }
@ -277,16 +294,16 @@ fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
/// Check the inherent impl's items for an `is_empty(self)` method. /// Check the inherent impl's items for an `is_empty(self)` method.
fn has_is_empty_impl(cx: &LateContext<'_, '_>, id: DefId) -> bool { fn has_is_empty_impl(cx: &LateContext<'_, '_>, id: DefId) -> bool {
cx.tcx.inherent_impls(id).iter().any(|imp| {
cx.tcx cx.tcx
.associated_items(*imp) .inherent_impls(id)
.any(|item| is_is_empty(cx, &item)) .iter()
}) .any(|imp| cx.tcx.associated_items(*imp).any(|item| is_is_empty(cx, &item)))
} }
let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr)); let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr));
match ty.sty { match ty.sty {
ty::Dynamic(ref tt, ..) => cx.tcx ty::Dynamic(ref tt, ..) => cx
.tcx
.associated_items(tt.principal().def_id()) .associated_items(tt.principal().def_id())
.any(|item| is_is_empty(cx, &item)), .any(|item| is_is_empty(cx, &item)),
ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id), ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),

View file

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir;
use crate::rustc::hir::def::Def;
use crate::rustc::hir::BindingAnnotation;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain; use crate::rustc_errors::Applicability;
use crate::rustc::hir;
use crate::rustc::hir::BindingAnnotation;
use crate::rustc::hir::def::Def;
use crate::syntax::ast; use crate::syntax::ast;
use crate::utils::{snippet, span_lint_and_then}; use crate::utils::{snippet, span_lint_and_then};
use crate::rustc_errors::Applicability; use if_chain::if_chain;
/// **What it does:** Checks for variable declarations immediately followed by a /// **What it does:** Checks for variable declarations immediately followed by a
/// conditional affectation. /// conditional affectation.
@ -207,11 +206,7 @@ fn check_assign<'a, 'tcx>(
} }
fn used_in_expr<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, id: ast::NodeId, expr: &'tcx hir::Expr) -> bool { fn used_in_expr<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, id: ast::NodeId, expr: &'tcx hir::Expr) -> bool {
let mut v = UsedVisitor { let mut v = UsedVisitor { cx, id, used: false };
cx,
id,
used: false,
};
hir::intravisit::walk_expr(&mut v, expr); hir::intravisit::walk_expr(&mut v, expr);
v.used v.used
} }

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// error-pattern:cargo-clippy // error-pattern:cargo-clippy
#![feature(box_syntax)] #![feature(box_syntax)]
@ -18,7 +17,6 @@
#![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::missing_docs_in_private_items)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#![feature(macro_at_most_once_rep)] #![feature(macro_at_most_once_rep)]
#![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)] #![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)]
#![feature(crate_visibility_modifier)] #![feature(crate_visibility_modifier)]
#![feature(try_from)] #![feature(try_from)]
@ -216,12 +214,19 @@ mod reexport {
crate use crate::syntax::ast::{Name, NodeId}; crate use crate::syntax::ast::{Name, NodeId};
} }
pub fn register_pre_expansion_lints(session: &rustc::session::Session, store: &mut rustc::lint::LintStore, conf: &Conf) { pub fn register_pre_expansion_lints(
session: &rustc::session::Session,
store: &mut rustc::lint::LintStore,
conf: &Conf,
) {
store.register_pre_expansion_pass(Some(session), box write::Pass); store.register_pre_expansion_pass(Some(session), box write::Pass);
store.register_pre_expansion_pass(Some(session), box redundant_field_names::RedundantFieldNames); store.register_pre_expansion_pass(Some(session), box redundant_field_names::RedundantFieldNames);
store.register_pre_expansion_pass(Some(session), box non_expressive_names::NonExpressiveNames { store.register_pre_expansion_pass(
Some(session),
box non_expressive_names::NonExpressiveNames {
single_char_binding_names_threshold: conf.single_char_binding_names_threshold, single_char_binding_names_threshold: conf.single_char_binding_names_threshold,
}); },
);
store.register_pre_expansion_pass(Some(session), box attrs::CfgAttrPass); store.register_pre_expansion_pass(Some(session), box attrs::CfgAttrPass);
} }
@ -236,13 +241,16 @@ pub fn read_conf(reg: &rustc_plugin::Registry<'_>) -> Conf {
match utils::conf::lookup_conf_file() { match utils::conf::lookup_conf_file() {
Ok(path) => path, Ok(path) => path,
Err(error) => { Err(error) => {
reg.sess.struct_err(&format!("error finding Clippy's configuration file: {}", error)).emit(); reg.sess
.struct_err(&format!("error finding Clippy's configuration file: {}", error))
.emit();
None None
} },
} }
}; };
let file_name = file_name.map(|file_name| if file_name.is_relative() { let file_name = file_name.map(|file_name| {
if file_name.is_relative() {
reg.sess reg.sess
.local_crate_source_file .local_crate_source_file
.as_ref() .as_ref()
@ -251,23 +259,31 @@ pub fn read_conf(reg: &rustc_plugin::Registry<'_>) -> Conf {
.join(file_name) .join(file_name)
} else { } else {
file_name file_name
}
}); });
let (conf, errors) = utils::conf::read(file_name.as_ref().map(|p| p.as_ref())); let (conf, errors) = utils::conf::read(file_name.as_ref().map(|p| p.as_ref()));
// all conf errors are non-fatal, we just use the default conf in case of error // all conf errors are non-fatal, we just use the default conf in case of error
for error in errors { for error in errors {
reg.sess.struct_err(&format!("error reading Clippy's configuration file `{}`: {}", file_name.as_ref().and_then(|p| p.to_str()).unwrap_or(""), error)).emit(); reg.sess
.struct_err(&format!(
"error reading Clippy's configuration file `{}`: {}",
file_name.as_ref().and_then(|p| p.to_str()).unwrap_or(""),
error
))
.emit();
} }
conf conf
} },
Err((err, span)) => { Err((err, span)) => {
reg.sess.struct_span_err(span, err) reg.sess
.struct_span_err(span, err)
.span_note(span, "Clippy will use default configuration") .span_note(span, "Clippy will use default configuration")
.emit(); .emit();
toml::from_str("").expect("we never error on empty config files") toml::from_str("").expect("we never error on empty config files")
} },
} }
} }

View file

@ -7,18 +7,17 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::reexport::*; use crate::reexport::*;
use matches::matches;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::def::Def; use crate::rustc::hir::def::Def;
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::*; use crate::rustc::hir::intravisit::*;
use crate::rustc::hir::*;
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet}; use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet};
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::{last_path_segment, span_lint};
use crate::syntax::symbol::keywords; use crate::syntax::symbol::keywords;
use crate::utils::{last_path_segment, span_lint};
use matches::matches;
/// **What it does:** Checks for lifetime annotations which can be removed by /// **What it does:** Checks for lifetime annotations which can be removed by
/// relying on lifetime elision. /// relying on lifetime elision.
@ -32,12 +31,14 @@ use crate::syntax::symbol::keywords;
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { x } /// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 {
/// x
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub NEEDLESS_LIFETIMES, pub NEEDLESS_LIFETIMES,
complexity, complexity,
"using explicit lifetimes for references in function arguments when elision rules \ "using explicit lifetimes for references in function arguments when elision rules \
would allow omitting them" would allow omitting them"
} }
@ -52,7 +53,9 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// fn unused_lifetime<'a>(x: u8) { .. } /// fn unused_lifetime<'a>(x: u8) {
/// ..
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub EXTRA_UNUSED_LIFETIMES, pub EXTRA_UNUSED_LIFETIMES,
@ -152,7 +155,8 @@ fn check_fn_inner<'a, 'tcx>(
cx, cx,
NEEDLESS_LIFETIMES, NEEDLESS_LIFETIMES,
span, span,
"explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)", "explicit lifetimes given in parameter types where they could be elided \
(or replaced with `'_` if needed by type declaration)",
); );
} }
report_extra_lifetimes(cx, decl, generics); report_extra_lifetimes(cx, decl, generics);
@ -220,9 +224,7 @@ fn could_use_elision<'a, 'tcx: 'a>(
// no output lifetimes, check distinctness of input lifetimes // no output lifetimes, check distinctness of input lifetimes
// only unnamed and static, ok // only unnamed and static, ok
let unnamed_and_static = input_lts let unnamed_and_static = input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
.iter()
.all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
if unnamed_and_static { if unnamed_and_static {
return false; return false;
} }
@ -320,7 +322,8 @@ impl<'v, 't> RefVisitor<'v, 't> {
&& !last_path_segment.args.iter().any(|arg| match arg { && !last_path_segment.args.iter().any(|arg| match arg {
GenericArg::Lifetime(_) => true, GenericArg::Lifetime(_) => true,
GenericArg::Type(_) => false, GenericArg::Type(_) => false,
}) { })
{
let hir_id = self.cx.tcx.hir.node_to_hir_id(ty.id); let hir_id = self.cx.tcx.hir.node_to_hir_id(ty.id);
match self.cx.tables.qpath_def(qpath, hir_id) { match self.cx.tables.qpath_def(qpath, hir_id) {
Def::TyAlias(def_id) | Def::Struct(def_id) => { Def::TyAlias(def_id) | Def::Struct(def_id) => {
@ -354,9 +357,8 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
self.record(&None); self.record(&None);
}, },
TyKind::Path(ref path) => { TyKind::Path(ref path) => {
self.collect_anonymous_lifetimes(path, ty); self.collect_anonymous_lifetimes(path, ty);
} },
TyKind::Def(item, _) => { TyKind::Def(item, _) => {
if let ItemKind::Existential(ref exist_ty) = self.cx.tcx.hir.expect_item(item.id).node { if let ItemKind::Existential(ref exist_ty) = self.cx.tcx.hir.expect_item(item.id).node {
for bound in &exist_ty.bounds { for bound in &exist_ty.bounds {
@ -368,7 +370,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
unreachable!() unreachable!()
} }
walk_ty(self, ty); walk_ty(self, ty);
} },
TyKind::TraitObject(ref bounds, ref lt) => { TyKind::TraitObject(ref bounds, ref lt) => {
if !lt.is_elided() { if !lt.is_elided() {
self.abort = true; self.abort = true;
@ -410,10 +412,12 @@ fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &
// and check that all lifetimes are allowed // and check that all lifetimes are allowed
match visitor.into_vec() { match visitor.into_vec() {
None => return false, None => return false,
Some(lts) => for lt in lts { Some(lts) => {
for lt in lts {
if !allowed_lts.contains(&lt) { if !allowed_lts.contains(&lt) {
return true; return true;
} }
}
}, },
} }
}, },
@ -456,7 +460,9 @@ impl<'tcx> Visitor<'tcx> for LifetimeChecker {
} }
fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx FnDecl, generics: &'tcx Generics) { fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx FnDecl, generics: &'tcx Generics) {
let hs = generics.params.iter() let hs = generics
.params
.iter()
.filter_map(|par| match par.kind { .filter_map(|par| match par.kind {
GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)), GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)),
_ => None, _ => None,
@ -468,7 +474,12 @@ fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx
walk_fn_decl(&mut checker, func); walk_fn_decl(&mut checker, func);
for &v in checker.map.values() { for &v in checker.map.values() {
span_lint(cx, EXTRA_UNUSED_LIFETIMES, v, "this lifetime isn't used in the function definition"); span_lint(
cx,
EXTRA_UNUSED_LIFETIMES,
v,
"this lifetime isn't used in the function definition",
);
} }
} }

View file

@ -414,9 +414,11 @@ impl LiteralDigitGrouping {
parts[0].len(), parts[0].len(),
parts[1].len()); parts[1].len());
if !consistent { if !consistent {
WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(), WarningType::InconsistentDigitGrouping.display(
&digit_info.grouping_hint(),
cx, cx,
lit.span); lit.span,
);
} }
}) })
.map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), .map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(),

View file

@ -7,33 +7,32 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use itertools::Itertools;
use crate::reexport::*; use crate::reexport::*;
use crate::rustc::hir::*;
use crate::rustc::hir::def::Def; use crate::rustc::hir::def::Def;
use crate::rustc::hir::def_id; use crate::rustc::hir::def_id;
use crate::rustc::hir::intravisit::{walk_block, walk_decl, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor}; use crate::rustc::hir::intravisit::{walk_block, walk_decl, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; use crate::rustc::hir::*;
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::middle::region;
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain; use if_chain::if_chain;
use crate::rustc::middle::region; use itertools::Itertools;
// use crate::rustc::middle::region::CodeExtent; // use crate::rustc::middle::region::CodeExtent;
use crate::consts::{constant, Constant};
use crate::rustc::middle::expr_use_visitor::*; use crate::rustc::middle::expr_use_visitor::*;
use crate::rustc::middle::mem_categorization::Categorization;
use crate::rustc::middle::mem_categorization::cmt_; use crate::rustc::middle::mem_categorization::cmt_;
use crate::rustc::ty::{self, Ty}; use crate::rustc::middle::mem_categorization::Categorization;
use crate::rustc::ty::subst::Subst; use crate::rustc::ty::subst::Subst;
use crate::rustc_errors::Applicability; use crate::rustc::ty::{self, Ty};
use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet}; use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet};
use std::iter::{once, Iterator}; use crate::rustc_errors::Applicability;
use std::mem;
use crate::syntax::ast; use crate::syntax::ast;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::syntax_pos::BytePos; use crate::syntax_pos::BytePos;
use crate::utils::{in_macro, sugg, sext};
use crate::utils::usage::mutated_variables; use crate::utils::usage::mutated_variables;
use crate::consts::{constant, Constant}; use crate::utils::{in_macro, sext, sugg};
use std::iter::{once, Iterator};
use std::mem;
use crate::utils::paths; use crate::utils::paths;
use crate::utils::{ use crate::utils::{
@ -92,11 +91,15 @@ declare_clippy_lint! {
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// // with `y` a `Vec` or slice: /// // with `y` a `Vec` or slice:
/// for x in y.iter() { .. } /// for x in y.iter() {
/// ..
/// }
/// ``` /// ```
/// can be rewritten to /// can be rewritten to
/// ```rust /// ```rust
/// for x in &y { .. } /// for x in &y {
/// ..
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub EXPLICIT_ITER_LOOP, pub EXPLICIT_ITER_LOOP,
@ -114,11 +117,15 @@ declare_clippy_lint! {
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// // with `y` a `Vec` or slice: /// // with `y` a `Vec` or slice:
/// for x in y.into_iter() { .. } /// for x in y.into_iter() {
/// ..
/// }
/// ``` /// ```
/// can be rewritten to /// can be rewritten to
/// ```rust /// ```rust
/// for x in y { .. } /// for x in y {
/// ..
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub EXPLICIT_INTO_ITER_LOOP, pub EXPLICIT_INTO_ITER_LOOP,
@ -139,7 +146,9 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// for x in y.next() { .. } /// for x in y.next() {
/// ..
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub ITER_NEXT_LOOP, pub ITER_NEXT_LOOP,
@ -156,12 +165,16 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// for x in option { .. } /// for x in option {
/// ..
/// }
/// ``` /// ```
/// ///
/// This should be /// This should be
/// ```rust /// ```rust
/// if let Some(x) = option { .. } /// if let Some(x) = option {
/// ..
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub FOR_LOOP_OVER_OPTION, pub FOR_LOOP_OVER_OPTION,
@ -178,12 +191,16 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// for x in result { .. } /// for x in result {
/// ..
/// }
/// ``` /// ```
/// ///
/// This should be /// This should be
/// ```rust /// ```rust
/// if let Ok(x) = result { .. } /// if let Ok(x) = result {
/// ..
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub FOR_LOOP_OVER_RESULT, pub FOR_LOOP_OVER_RESULT,
@ -234,8 +251,7 @@ declare_clippy_lint! {
declare_clippy_lint! { declare_clippy_lint! {
pub UNUSED_COLLECT, pub UNUSED_COLLECT,
perf, perf,
"`collect()`ing an iterator without using the result; this is usually better \ "`collect()`ing an iterator without using the result; this is usually better written as a for loop"
written as a for loop"
} }
/// **What it does:** Checks for functions collecting an iterator when collect /// **What it does:** Checks for functions collecting an iterator when collect
@ -273,7 +289,9 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// for x in 5..10-5 { .. } // oops, stray `-` /// for x in 5..10 - 5 {
/// ..
/// } // oops, stray `-`
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub REVERSE_RANGE_LOOP, pub REVERSE_RANGE_LOOP,
@ -328,7 +346,9 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// while let Some(val) = iter() { .. } /// while let Some(val) = iter() {
/// ..
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub WHILE_LET_ON_ITERATOR, pub WHILE_LET_ON_ITERATOR,
@ -346,13 +366,17 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// for (k, _) in &map { .. } /// for (k, _) in &map {
/// ..
/// }
/// ``` /// ```
/// ///
/// could be replaced by /// could be replaced by
/// ///
/// ```rust /// ```rust
/// for k in map.keys() { .. } /// for k in map.keys() {
/// ..
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub FOR_KV_MAP, pub FOR_KV_MAP,
@ -370,7 +394,10 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// loop { ..; break; } /// loop {
/// ..;
/// break;
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub NEVER_LOOP, pub NEVER_LOOP,
@ -459,8 +486,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
match expr.node { match expr.node {
ExprKind::While(_, ref block, _) | ExprKind::Loop(ref block, _, _) => { ExprKind::While(_, ref block, _) | ExprKind::Loop(ref block, _, _) => {
match never_loop_block(block, expr.id) { match never_loop_block(block, expr.id) {
NeverLoopResult::AlwaysBreak => NeverLoopResult::AlwaysBreak => {
span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"), span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops")
},
NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (), NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
} }
}, },
@ -490,8 +518,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
// ensure "if let" compatible match structure // ensure "if let" compatible match structure
match *source { match *source {
MatchSource::Normal | MatchSource::IfLetDesugar { .. } => { MatchSource::Normal | MatchSource::IfLetDesugar { .. } => {
if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none() if arms.len() == 2
&& arms[1].pats.len() == 1 && arms[1].guard.is_none() && arms[0].pats.len() == 1
&& arms[0].guard.is_none()
&& arms[1].pats.len() == 1
&& arms[1].guard.is_none()
&& is_simple_break_expr(&arms[1].body) && is_simple_break_expr(&arms[1].body)
{ {
if in_external_macro(cx.sess(), expr.span) { if in_external_macro(cx.sess(), expr.span) {
@ -533,9 +564,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
{ {
let iter_expr = &method_args[0]; let iter_expr = &method_args[0];
let lhs_constructor = last_path_segment(qpath); let lhs_constructor = last_path_segment(qpath);
if method_path.ident.name == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR) if method_path.ident.name == "next"
&& lhs_constructor.ident.name == "Some" && ( && match_trait_method(cx, match_expr, &paths::ITERATOR)
pat_args.is_empty() && lhs_constructor.ident.name == "Some"
&& (pat_args.is_empty()
|| !is_refutable(cx, &pat_args[0]) || !is_refutable(cx, &pat_args[0])
&& !is_iterator_used_after_while_let(cx, iter_expr) && !is_iterator_used_after_while_let(cx, iter_expr)
&& !is_nested(cx, expr, &method_args[0])) && !is_nested(cx, expr, &method_args[0]))
@ -594,8 +626,7 @@ enum NeverLoopResult {
fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult { fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult {
match *arg { match *arg {
NeverLoopResult::AlwaysBreak | NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop, NeverLoopResult::MayContinueMainLoop => NeverLoopResult::MayContinueMainLoop,
} }
} }
@ -611,24 +642,22 @@ fn combine_seq(first: NeverLoopResult, second: NeverLoopResult) -> NeverLoopResu
// Combine two results where both parts are called but not necessarily in order. // Combine two results where both parts are called but not necessarily in order.
fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResult { fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResult {
match (left, right) { match (left, right) {
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
NeverLoopResult::MayContinueMainLoop, NeverLoopResult::MayContinueMainLoop
(NeverLoopResult::AlwaysBreak, _) | (_, NeverLoopResult::AlwaysBreak) => },
NeverLoopResult::AlwaysBreak, (NeverLoopResult::AlwaysBreak, _) | (_, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
(NeverLoopResult::Otherwise, NeverLoopResult::Otherwise) => (NeverLoopResult::Otherwise, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
NeverLoopResult::Otherwise,
} }
} }
// Combine two results where only one of the part may have been executed. // Combine two results where only one of the part may have been executed.
fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult { fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult {
match (b1, b2) { match (b1, b2) {
(NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => (NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
NeverLoopResult::AlwaysBreak, (NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => NeverLoopResult::MayContinueMainLoop
NeverLoopResult::MayContinueMainLoop, },
(NeverLoopResult::Otherwise, _) | (_, NeverLoopResult::Otherwise) => (NeverLoopResult::Otherwise, _) | (_, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
NeverLoopResult::Otherwise,
} }
} }
@ -655,26 +684,28 @@ fn decl_to_expr(decl: &Decl) -> Option<&Expr> {
fn never_loop_expr(expr: &Expr, main_loop_id: NodeId) -> NeverLoopResult { fn never_loop_expr(expr: &Expr, main_loop_id: NodeId) -> NeverLoopResult {
match expr.node { match expr.node {
ExprKind::Box(ref e) | ExprKind::Box(ref e)
ExprKind::Unary(_, ref e) | | ExprKind::Unary(_, ref e)
ExprKind::Cast(ref e, _) | | ExprKind::Cast(ref e, _)
ExprKind::Type(ref e, _) | | ExprKind::Type(ref e, _)
ExprKind::Field(ref e, _) | | ExprKind::Field(ref e, _)
ExprKind::AddrOf(_, ref e) | | ExprKind::AddrOf(_, ref e)
ExprKind::Struct(_, _, Some(ref e)) | | ExprKind::Struct(_, _, Some(ref e))
ExprKind::Repeat(ref e, _) => never_loop_expr(e, main_loop_id), | ExprKind::Repeat(ref e, _) => never_loop_expr(e, main_loop_id),
ExprKind::Array(ref es) | ExprKind::MethodCall(_, _, ref es) | ExprKind::Tup(ref es) => { ExprKind::Array(ref es) | ExprKind::MethodCall(_, _, ref es) | ExprKind::Tup(ref es) => {
never_loop_expr_all(&mut es.iter(), main_loop_id) never_loop_expr_all(&mut es.iter(), main_loop_id)
}, },
ExprKind::Call(ref e, ref es) => never_loop_expr_all(&mut once(&**e).chain(es.iter()), main_loop_id), ExprKind::Call(ref e, ref es) => never_loop_expr_all(&mut once(&**e).chain(es.iter()), main_loop_id),
ExprKind::Binary(_, ref e1, ref e2) | ExprKind::Binary(_, ref e1, ref e2)
ExprKind::Assign(ref e1, ref e2) | | ExprKind::Assign(ref e1, ref e2)
ExprKind::AssignOp(_, ref e1, ref e2) | | ExprKind::AssignOp(_, ref e1, ref e2)
ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id), | ExprKind::Index(ref e1, ref e2) => never_loop_expr_all(&mut [&**e1, &**e2].iter().cloned(), main_loop_id),
ExprKind::If(ref e, ref e2, ref e3) => { ExprKind::If(ref e, ref e2, ref e3) => {
let e1 = never_loop_expr(e, main_loop_id); let e1 = never_loop_expr(e, main_loop_id);
let e2 = never_loop_expr(e2, main_loop_id); let e2 = never_loop_expr(e2, main_loop_id);
let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| never_loop_expr(e, main_loop_id)); let e3 = e3
.as_ref()
.map_or(NeverLoopResult::Otherwise, |e| never_loop_expr(e, main_loop_id));
combine_seq(e1, combine_branches(e2, e3)) combine_seq(e1, combine_branches(e2, e3))
}, },
ExprKind::Loop(ref b, _, _) => { ExprKind::Loop(ref b, _, _) => {
@ -698,7 +729,8 @@ fn never_loop_expr(expr: &Expr, main_loop_id: NodeId) -> NeverLoopResult {
}, },
ExprKind::Block(ref b, _) => never_loop_block(b, main_loop_id), ExprKind::Block(ref b, _) => never_loop_block(b, main_loop_id),
ExprKind::Continue(d) => { ExprKind::Continue(d) => {
let id = d.target_id let id = d
.target_id
.expect("target id can only be missing in the presence of compilation errors"); .expect("target id can only be missing in the presence of compilation errors");
if id == main_loop_id { if id == main_loop_id {
NeverLoopResult::MayContinueMainLoop NeverLoopResult::MayContinueMainLoop
@ -706,9 +738,7 @@ fn never_loop_expr(expr: &Expr, main_loop_id: NodeId) -> NeverLoopResult {
NeverLoopResult::AlwaysBreak NeverLoopResult::AlwaysBreak
} }
}, },
ExprKind::Break(_, _) => { ExprKind::Break(_, _) => NeverLoopResult::AlwaysBreak,
NeverLoopResult::AlwaysBreak
},
ExprKind::Ret(ref e) => { ExprKind::Ret(ref e) => {
if let Some(ref e) = *e { if let Some(ref e) = *e {
combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak) combine_seq(never_loop_expr(e, main_loop_id), NeverLoopResult::AlwaysBreak)
@ -716,26 +746,26 @@ fn never_loop_expr(expr: &Expr, main_loop_id: NodeId) -> NeverLoopResult {
NeverLoopResult::AlwaysBreak NeverLoopResult::AlwaysBreak
} }
}, },
ExprKind::Struct(_, _, None) | ExprKind::Struct(_, _, None)
ExprKind::Yield(_) | | ExprKind::Yield(_)
ExprKind::Closure(_, _, _, _, _) | | ExprKind::Closure(_, _, _, _, _)
ExprKind::InlineAsm(_, _, _) | | ExprKind::InlineAsm(_, _, _)
ExprKind::Path(_) | | ExprKind::Path(_)
ExprKind::Lit(_) => NeverLoopResult::Otherwise, | ExprKind::Lit(_) => NeverLoopResult::Otherwise,
} }
} }
fn never_loop_expr_seq<'a, T: Iterator<Item=&'a Expr>>(es: &mut T, main_loop_id: NodeId) -> NeverLoopResult { fn never_loop_expr_seq<'a, T: Iterator<Item = &'a Expr>>(es: &mut T, main_loop_id: NodeId) -> NeverLoopResult {
es.map(|e| never_loop_expr(e, main_loop_id)) es.map(|e| never_loop_expr(e, main_loop_id))
.fold(NeverLoopResult::Otherwise, combine_seq) .fold(NeverLoopResult::Otherwise, combine_seq)
} }
fn never_loop_expr_all<'a, T: Iterator<Item=&'a Expr>>(es: &mut T, main_loop_id: NodeId) -> NeverLoopResult { fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr>>(es: &mut T, main_loop_id: NodeId) -> NeverLoopResult {
es.map(|e| never_loop_expr(e, main_loop_id)) es.map(|e| never_loop_expr(e, main_loop_id))
.fold(NeverLoopResult::Otherwise, combine_both) .fold(NeverLoopResult::Otherwise, combine_both)
} }
fn never_loop_expr_branch<'a, T: Iterator<Item=&'a Expr>>(e: &mut T, main_loop_id: NodeId) -> NeverLoopResult { fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr>>(e: &mut T, main_loop_id: NodeId) -> NeverLoopResult {
e.map(|e| never_loop_expr(e, main_loop_id)) e.map(|e| never_loop_expr(e, main_loop_id))
.fold(NeverLoopResult::AlwaysBreak, combine_branches) .fold(NeverLoopResult::AlwaysBreak, combine_branches)
} }
@ -779,10 +809,7 @@ struct Offset {
impl Offset { impl Offset {
fn negative(s: String) -> Self { fn negative(s: String) -> Self {
Self { Self { value: s, negate: true }
value: s,
negate: true,
}
} }
fn positive(s: String) -> Self { fn positive(s: String) -> Self {
@ -842,19 +869,19 @@ fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var:
BinOpKind::Sub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative), BinOpKind::Sub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative),
_ => None, _ => None,
}, },
ExprKind::Path(..) => if same_var(cx, idx, var) { ExprKind::Path(..) => {
if same_var(cx, idx, var) {
Some(Offset::positive("0".into())) Some(Offset::positive("0".into()))
} else { } else {
None None
}
}, },
_ => None, _ => None,
}; };
offset.map(|o| { offset.map(|o| FixedOffsetVar {
FixedOffsetVar {
var_name: snippet_opt(cx, seqexpr.span).unwrap_or_else(|| "???".into()), var_name: snippet_opt(cx, seqexpr.span).unwrap_or_else(|| "???".into()),
offset: o, offset: o,
}
}) })
} else { } else {
None None
@ -890,7 +917,10 @@ fn get_indexed_assignments<'a, 'tcx>(
var: ast::NodeId, var: ast::NodeId,
) -> Option<(FixedOffsetVar, FixedOffsetVar)> { ) -> Option<(FixedOffsetVar, FixedOffsetVar)> {
if let ExprKind::Assign(ref lhs, ref rhs) = e.node { if let ExprKind::Assign(ref lhs, ref rhs) = e.node {
match (get_fixed_offset_var(cx, lhs, var), fetch_cloned_fixed_offset_var(cx, rhs, var)) { match (
get_fixed_offset_var(cx, lhs, var),
fetch_cloned_fixed_offset_var(cx, rhs, var),
) {
(Some(offset_left), Some(offset_right)) => { (Some(offset_left), Some(offset_right)) => {
// Source and destination must be different // Source and destination must be different
if offset_left.var_name == offset_right.var_name { if offset_left.var_name == offset_right.var_name {
@ -908,9 +938,7 @@ fn get_indexed_assignments<'a, 'tcx>(
if let ExprKind::Block(ref b, _) = body.node { if let ExprKind::Block(ref b, _) = body.node {
let Block { let Block {
ref stmts, ref stmts, ref expr, ..
ref expr,
..
} = **b; } = **b;
stmts stmts
@ -919,11 +947,7 @@ fn get_indexed_assignments<'a, 'tcx>(
StmtKind::Decl(..) => None, StmtKind::Decl(..) => None,
StmtKind::Expr(ref e, _node_id) | StmtKind::Semi(ref e, _node_id) => Some(get_assignment(cx, e, var)), StmtKind::Expr(ref e, _node_id) | StmtKind::Semi(ref e, _node_id) => Some(get_assignment(cx, e, var)),
}) })
.chain( .chain(expr.as_ref().into_iter().map(|e| Some(get_assignment(cx, &*e, var))))
expr.as_ref()
.into_iter()
.map(|e| Some(get_assignment(cx, &*e, var))),
)
.filter_map(|op| op) .filter_map(|op| op)
.collect::<Option<Vec<_>>>() .collect::<Option<Vec<_>>>()
.unwrap_or_else(|| vec![]) .unwrap_or_else(|| vec![])
@ -973,7 +997,8 @@ fn detect_manual_memcpy<'a, 'tcx>(
} }
}; };
let print_limit = |end: &Option<&Expr>, offset: Offset, var_name: &str| if let Some(end) = *end { let print_limit = |end: &Option<&Expr>, offset: Offset, var_name: &str| {
if let Some(end) = *end {
if_chain! { if_chain! {
if let ExprKind::MethodCall(ref method, _, ref len_args) = end.node; if let ExprKind::MethodCall(ref method, _, ref len_args) = end.node;
if method.ident.name == "len"; if method.ident.name == "len";
@ -1000,6 +1025,7 @@ fn detect_manual_memcpy<'a, 'tcx>(
print_sum(&Offset::positive(end_str), &offset) print_sum(&Offset::positive(end_str), &offset)
} else { } else {
"..".into() "..".into()
}
}; };
// The only statements in the for loops can be indexed assignments from // The only statements in the for loops can be indexed assignments from
@ -1020,7 +1046,10 @@ fn detect_manual_memcpy<'a, 'tcx>(
format!("{}[{}..{}]", dst_var.var_name, dst_offset, dst_limit) format!("{}[{}..{}]", dst_var.var_name, dst_offset, dst_limit)
}; };
format!("{}.clone_from_slice(&{}[{}..{}])", dst, src_var.var_name, src_offset, src_limit) format!(
"{}.clone_from_slice(&{}[{}..{}])",
dst, src_var.var_name, src_offset, src_limit
)
}) })
.join("\n "); .join("\n ");
@ -1166,7 +1195,10 @@ fn check_for_loop_range<'a, 'tcx>(
"consider using an iterator".to_string(), "consider using an iterator".to_string(),
vec![ vec![
(pat.span, format!("({}, <item>)", ident.name)), (pat.span, format!("({}, <item>)", ident.name)),
(arg.span, format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2)), (
arg.span,
format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2),
),
], ],
); );
}, },
@ -1182,7 +1214,10 @@ fn check_for_loop_range<'a, 'tcx>(
cx, cx,
NEEDLESS_RANGE_LOOP, NEEDLESS_RANGE_LOOP,
expr.span, expr.span,
&format!("the loop variable `{}` is only used to index `{}`.", ident.name, indexed), &format!(
"the loop variable `{}` is only used to index `{}`.",
ident.name, indexed
),
|db| { |db| {
multispan_sugg( multispan_sugg(
db, db,
@ -1213,12 +1248,7 @@ fn is_len_call(expr: &Expr, var: Name) -> bool {
false false
} }
fn is_end_eq_array_len( fn is_end_eq_array_len(cx: &LateContext<'_, '_>, end: &Expr, limits: ast::RangeLimits, indexed_ty: Ty<'_>) -> bool {
cx: &LateContext<'_, '_>,
end: &Expr,
limits: ast::RangeLimits,
indexed_ty: Ty<'_>,
) -> bool {
if_chain! { if_chain! {
if let ExprKind::Lit(ref lit) = end.node; if let ExprKind::Lit(ref lit) = end.node;
if let ast::LitKind::Int(end_int, _) = lit.node; if let ast::LitKind::Int(end_int, _) = lit.node;
@ -1252,14 +1282,14 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx
// smaller value. // smaller value.
let ty = cx.tables.expr_ty(start); let ty = cx.tables.expr_ty(start);
let (sup, eq) = match (start_idx, end_idx) { let (sup, eq) = match (start_idx, end_idx) {
( (Constant::Int(start_idx), Constant::Int(end_idx)) => (
Constant::Int(start_idx), match ty.sty {
Constant::Int(end_idx),
) => (match ty.sty {
ty::Int(ity) => sext(cx.tcx, start_idx, ity) > sext(cx.tcx, end_idx, ity), ty::Int(ity) => sext(cx.tcx, start_idx, ity) > sext(cx.tcx, end_idx, ity),
ty::Uint(_) => start_idx > end_idx, ty::Uint(_) => start_idx > end_idx,
_ => false, _ => false,
}, start_idx == end_idx), },
start_idx == end_idx,
),
_ => (false, false), _ => (false, false),
}; };
@ -1310,11 +1340,7 @@ fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx
fn lint_iter_method(cx: &LateContext<'_, '_>, args: &[Expr], arg: &Expr, method_name: &str) { fn lint_iter_method(cx: &LateContext<'_, '_>, args: &[Expr], arg: &Expr, method_name: &str) {
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
let muta = if method_name == "iter_mut" { let muta = if method_name == "iter_mut" { "mut " } else { "" };
"mut "
} else {
""
};
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
EXPLICIT_ITER_LOOP, EXPLICIT_ITER_LOOP,
@ -1439,15 +1465,12 @@ fn check_for_loop_explicit_counter<'a, 'tcx>(
// For each candidate, check the parent block to see if // For each candidate, check the parent block to see if
// it's initialized to zero at the start of the loop. // it's initialized to zero at the start of the loop.
let map = &cx.tcx.hir; let map = &cx.tcx.hir;
let parent_scope = map.get_enclosing_scope(expr.id) let parent_scope = map
.get_enclosing_scope(expr.id)
.and_then(|id| map.get_enclosing_scope(id)); .and_then(|id| map.get_enclosing_scope(id));
if let Some(parent_id) = parent_scope { if let Some(parent_id) = parent_scope {
if let Node::Block(block) = map.get(parent_id) { if let Node::Block(block) = map.get(parent_id) {
for (id, _) in visitor for (id, _) in visitor.states.iter().filter(|&(_, v)| *v == VarState::IncrOnce) {
.states
.iter()
.filter(|&(_, v)| *v == VarState::IncrOnce)
{
let mut visitor2 = InitializeVisitor { let mut visitor2 = InitializeVisitor {
cx, cx,
end_expr: expr, end_expr: expr,
@ -1586,10 +1609,7 @@ fn check_for_mut_range_bound(cx: &LateContext<'_, '_>, arg: &Expr, body: &Expr)
.. ..
}) = higher::range(cx, arg) }) = higher::range(cx, arg)
{ {
let mut_ids = vec![ let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
check_for_mutability(cx, start),
check_for_mutability(cx, end),
];
if mut_ids[0].is_some() || mut_ids[1].is_some() { if mut_ids[0].is_some() || mut_ids[1].is_some() {
let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids); let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids);
mut_warn_with_span(cx, span_low); mut_warn_with_span(cx, span_low);
@ -1631,7 +1651,11 @@ fn check_for_mutability(cx: &LateContext<'_, '_>, bound: &Expr) -> Option<NodeId
None None
} }
fn check_for_mutation(cx: &LateContext<'_, '_>, body: &Expr, bound_ids: &[Option<NodeId>]) -> (Option<Span>, Option<Span>) { fn check_for_mutation(
cx: &LateContext<'_, '_>,
body: &Expr,
bound_ids: &[Option<NodeId>],
) -> (Option<Span>, Option<Span>) {
let mut delegate = MutatePairDelegate { let mut delegate = MutatePairDelegate {
node_id_low: bound_ids[0], node_id_low: bound_ids[0],
node_id_high: bound_ids[1], node_id_high: bound_ids[1],
@ -1821,8 +1845,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
} }
let old = self.prefer_mutable; let old = self.prefer_mutable;
match expr.node { match expr.node {
ExprKind::AssignOp(_, ref lhs, ref rhs) | ExprKind::AssignOp(_, ref lhs, ref rhs) | ExprKind::Assign(ref lhs, ref rhs) => {
ExprKind::Assign(ref lhs, ref rhs) => {
self.prefer_mutable = true; self.prefer_mutable = true;
self.visit_expr(lhs); self.visit_expr(lhs);
self.prefer_mutable = false; self.prefer_mutable = false;
@ -1910,7 +1933,6 @@ impl<'a, 'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor<'a, 'tcx> {
} }
} }
/// Return true if the type of expr is one that provides `IntoIterator` impls /// Return true if the type of expr is one that provides `IntoIterator` impls
/// for `&T` and `&mut T`, such as `Vec`. /// for `&T` and `&mut T`, such as `Vec`.
#[rustfmt::skip] #[rustfmt::skip]
@ -2244,8 +2266,10 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
return; return;
} }
match expr.node { match expr.node {
ExprKind::Assign(ref path, _) | ExprKind::AssignOp(_, ref path, _) => if match_var(path, self.iterator) { ExprKind::Assign(ref path, _) | ExprKind::AssignOp(_, ref path, _) => {
if match_var(path, self.iterator) {
self.nesting = RuledOut; self.nesting = RuledOut;
}
}, },
_ => walk_expr(self, expr), _ => walk_expr(self, expr),
} }
@ -2299,7 +2323,7 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, e
let no_cond_variable_mutated = if let Some(used_mutably) = mutated_variables(expr, cx) { let no_cond_variable_mutated = if let Some(used_mutably) = mutated_variables(expr, cx) {
used_in_condition.is_disjoint(&used_mutably) used_in_condition.is_disjoint(&used_mutably)
} else { } else {
return return;
}; };
let mutable_static_in_cond = var_visitor.def_ids.iter().any(|(_, v)| *v); let mutable_static_in_cond = var_visitor.def_ids.iter().any(|(_, v)| *v);
if no_cond_variable_mutated && !mutable_static_in_cond { if no_cond_variable_mutated && !mutable_static_in_cond {
@ -2307,7 +2331,8 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, e
cx, cx,
WHILE_IMMUTABLE_CONDITION, WHILE_IMMUTABLE_CONDITION,
cond.span, cond.span,
"Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.", "Variable in the condition are not mutated in the loop body. \
This either leads to an infinite or to a never running loop.",
); );
} }
} }

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
@ -15,7 +14,9 @@ use crate::rustc_errors::Applicability;
use crate::syntax::ast::Ident; use crate::syntax::ast::Ident;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::paths; use crate::utils::paths;
use crate::utils::{in_macro, match_trait_method, match_type, remove_blocks, snippet_with_applicability, span_lint_and_sugg}; use crate::utils::{
in_macro, match_trait_method, match_type, remove_blocks, snippet_with_applicability, span_lint_and_sugg,
};
use if_chain::if_chain; use if_chain::if_chain;
#[derive(Clone)] #[derive(Clone)]
@ -72,15 +73,26 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
let closure_expr = remove_blocks(&closure_body.value); let closure_expr = remove_blocks(&closure_body.value);
then { then {
match closure_body.arguments[0].pat.node { match closure_body.arguments[0].pat.node {
hir::PatKind::Ref(ref inner, _) => if let hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) = inner.node { hir::PatKind::Ref(ref inner, _) => if let hir::PatKind::Binding(
hir::BindingAnnotation::Unannotated, _, name, None
) = inner.node {
lint(cx, e.span, args[0].span, name, closure_expr); lint(cx, e.span, args[0].span, name, closure_expr);
}, },
hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => match closure_expr.node { hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => {
hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) if !cx.tables.expr_ty(inner).is_box() => lint(cx, e.span, args[0].span, name, inner), match closure_expr.node {
hir::ExprKind::MethodCall(ref method, _, ref obj) => if method.ident.as_str() == "clone" && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) { hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner) => {
if !cx.tables.expr_ty(inner).is_box() {
lint(cx, e.span, args[0].span, name, inner);
}
},
hir::ExprKind::MethodCall(ref method, _, ref obj) => {
if method.ident.as_str() == "clone"
&& match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) {
lint(cx, e.span, args[0].span, name, &obj[0]); lint(cx, e.span, args[0].span, name, &obj[0]);
} }
},
_ => {}, _ => {},
}
}, },
_ => {}, _ => {},
} }
@ -99,7 +111,10 @@ fn lint(cx: &LateContext<'_, '_>, replace: Span, root: Span, name: Ident, path:
replace, replace,
"You are using an explicit closure for cloning elements", "You are using an explicit closure for cloning elements",
"Consider calling the dedicated `cloned` method", "Consider calling the dedicated `cloned` method",
format!("{}.cloned()", snippet_with_applicability(cx, root, "..", &mut applicability)), format!(
"{}.cloned()",
snippet_with_applicability(cx, root, "..", &mut applicability)
),
applicability, applicability,
) )
} }

View file

@ -7,16 +7,15 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty; use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::{in_macro, iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then};
use crate::utils::paths; use crate::utils::paths;
use crate::utils::{in_macro, iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then};
use if_chain::if_chain;
#[derive(Clone)] #[derive(Clone)]
pub struct Pass; pub struct Pass;
@ -87,7 +86,6 @@ declare_clippy_lint! {
"using `result.map(f)`, where f is a function or closure that returns ()" "using `result.map(f)`, where f is a function or closure that returns ()"
} }
impl LintPass for Pass { impl LintPass for Pass {
fn get_lints(&self) -> LintArray { fn get_lints(&self) -> LintArray {
lint_array!(OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN) lint_array!(OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN)
@ -127,8 +125,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a hir::Expr) ->
} }
match expr.node { match expr.node {
hir::ExprKind::Call(_, _) | hir::ExprKind::Call(_, _) | hir::ExprKind::MethodCall(_, _, _) => {
hir::ExprKind::MethodCall(_, _, _) => {
// Calls can't be reduced any more // Calls can't be reduced any more
Some(expr.span) Some(expr.span)
}, },
@ -155,7 +152,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a hir::Expr) ->
// //
// We do not attempt to build a suggestion for those right now. // We do not attempt to build a suggestion for those right now.
None None
} },
} }
}, },
_ => None, _ => None,
@ -189,15 +186,14 @@ fn let_binding_name(cx: &LateContext<'_, '_>, var_arg: &hir::Expr) -> String {
match &var_arg.node { match &var_arg.node {
hir::ExprKind::Field(_, _) => snippet(cx, var_arg.span, "_").replace(".", "_"), hir::ExprKind::Field(_, _) => snippet(cx, var_arg.span, "_").replace(".", "_"),
hir::ExprKind::Path(_) => format!("_{}", snippet(cx, var_arg.span, "")), hir::ExprKind::Path(_) => format!("_{}", snippet(cx, var_arg.span, "")),
_ => "_".to_string() _ => "_".to_string(),
} }
} }
fn suggestion_msg(function_type: &str, map_type: &str) -> String { fn suggestion_msg(function_type: &str, map_type: &str) -> String {
format!( format!(
"called `map(f)` on an {0} value where `f` is a unit {1}", "called `map(f)` on an {0} value where `f` is a unit {1}",
map_type, map_type, function_type
function_type
) )
} }
@ -205,39 +201,39 @@ fn lint_map_unit_fn(cx: &LateContext<'_, '_>, stmt: &hir::Stmt, expr: &hir::Expr
let var_arg = &map_args[0]; let var_arg = &map_args[0];
let fn_arg = &map_args[1]; let fn_arg = &map_args[1];
let (map_type, variant, lint) = let (map_type, variant, lint) = if match_type(cx, cx.tables.expr_ty(var_arg), &paths::OPTION) {
if match_type(cx, cx.tables.expr_ty(var_arg), &paths::OPTION) {
("Option", "Some", OPTION_MAP_UNIT_FN) ("Option", "Some", OPTION_MAP_UNIT_FN)
} else if match_type(cx, cx.tables.expr_ty(var_arg), &paths::RESULT) { } else if match_type(cx, cx.tables.expr_ty(var_arg), &paths::RESULT) {
("Result", "Ok", RESULT_MAP_UNIT_FN) ("Result", "Ok", RESULT_MAP_UNIT_FN)
} else { } else {
return return;
}; };
if is_unit_function(cx, fn_arg) { if is_unit_function(cx, fn_arg) {
let msg = suggestion_msg("function", map_type); let msg = suggestion_msg("function", map_type);
let suggestion = format!("if let {0}({1}) = {2} {{ {3}(...) }}", let suggestion = format!(
"if let {0}({1}) = {2} {{ {3}(...) }}",
variant, variant,
let_binding_name(cx, var_arg), let_binding_name(cx, var_arg),
snippet(cx, var_arg.span, "_"), snippet(cx, var_arg.span, "_"),
snippet(cx, fn_arg.span, "_")); snippet(cx, fn_arg.span, "_")
);
span_lint_and_then(cx, lint, expr.span, &msg, |db| { span_lint_and_then(cx, lint, expr.span, &msg, |db| {
db.span_suggestion_with_applicability(stmt.span, db.span_suggestion_with_applicability(stmt.span, "try this", suggestion, Applicability::Unspecified);
"try this",
suggestion,
Applicability::Unspecified);
}); });
} else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) { } else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) {
let msg = suggestion_msg("closure", map_type); let msg = suggestion_msg("closure", map_type);
span_lint_and_then(cx, lint, expr.span, &msg, |db| { span_lint_and_then(cx, lint, expr.span, &msg, |db| {
if let Some(reduced_expr_span) = reduce_unit_expression(cx, closure_expr) { if let Some(reduced_expr_span) = reduce_unit_expression(cx, closure_expr) {
let suggestion = format!("if let {0}({1}) = {2} {{ {3} }}", let suggestion = format!(
"if let {0}({1}) = {2} {{ {3} }}",
variant, variant,
snippet(cx, binding.pat.span, "_"), snippet(cx, binding.pat.span, "_"),
snippet(cx, var_arg.span, "_"), snippet(cx, var_arg.span, "_"),
snippet(cx, reduced_expr_span, "_")); snippet(cx, reduced_expr_span, "_")
);
db.span_suggestion_with_applicability( db.span_suggestion_with_applicability(
stmt.span, stmt.span,
"try this", "try this",
@ -245,16 +241,13 @@ fn lint_map_unit_fn(cx: &LateContext<'_, '_>, stmt: &hir::Stmt, expr: &hir::Expr
Applicability::MachineApplicable, // snippet Applicability::MachineApplicable, // snippet
); );
} else { } else {
let suggestion = format!("if let {0}({1}) = {2} {{ ... }}", let suggestion = format!(
"if let {0}({1}) = {2} {{ ... }}",
variant, variant,
snippet(cx, binding.pat.span, "_"), snippet(cx, binding.pat.span, "_"),
snippet(cx, var_arg.span, "_")); snippet(cx, var_arg.span, "_")
db.span_suggestion_with_applicability(
stmt.span,
"try this",
suggestion,
Applicability::Unspecified,
); );
db.span_suggestion_with_applicability(stmt.span, "try this", suggestion, Applicability::Unspecified);
} }
}); });
} }

View file

@ -7,23 +7,23 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::consts::{constant, Constant};
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty::{self, Ty}; use crate::rustc::ty::{self, Ty};
use std::cmp::Ordering; use crate::rustc::{declare_tool_lint, lint_array};
use std::collections::Bound; use crate::rustc_errors::Applicability;
use crate::syntax::ast::LitKind; use crate::syntax::ast::LitKind;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::paths; use crate::utils::paths;
use crate::utils::{expr_block, in_macro, is_allowed, is_expn_of, match_qpath, match_type,
multispan_sugg, remove_blocks, snippet, snippet_with_applicability, span_lint_and_sugg, span_lint_and_then,
span_note_and_lint, walk_ptrs_ty};
use crate::utils::sugg::Sugg; use crate::utils::sugg::Sugg;
use crate::consts::{constant, Constant}; use crate::utils::{
use crate::rustc_errors::Applicability; expr_block, in_macro, is_allowed, is_expn_of, match_qpath, match_type, multispan_sugg, remove_blocks, snippet,
snippet_with_applicability, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty,
};
use if_chain::if_chain;
use std::cmp::Ordering;
use std::collections::Bound;
/// **What it does:** Checks for matches with a single arm where an `if let` /// **What it does:** Checks for matches with a single arm where an `if let`
/// will usually suffice. /// will usually suffice.
@ -36,14 +36,13 @@ use crate::rustc_errors::Applicability;
/// ```rust /// ```rust
/// match x { /// match x {
/// Some(ref foo) => bar(foo), /// Some(ref foo) => bar(foo),
/// _ => () /// _ => (),
/// } /// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub SINGLE_MATCH, pub SINGLE_MATCH,
style, style,
"a match statement with a single nontrivial arm (i.e. where the other arm \ "a match statement with a single nontrivial arm (i.e. where the other arm is `_ => {}`) instead of `if let`"
is `_ => {}`) instead of `if let`"
} }
/// **What it does:** Checks for matches with a two arms where an `if let` will /// **What it does:** Checks for matches with a two arms where an `if let` will
@ -63,8 +62,7 @@ declare_clippy_lint! {
declare_clippy_lint! { declare_clippy_lint! {
pub SINGLE_MATCH_ELSE, pub SINGLE_MATCH_ELSE,
pedantic, pedantic,
"a match statement with a two arms where the second arm's pattern is a wildcard \ "a match statement with a two arms where the second arm's pattern is a wildcard instead of `if let`"
instead of `if let`"
} }
/// **What it does:** Checks for matches where all arms match a reference, /// **What it does:** Checks for matches where all arms match a reference,
@ -131,8 +129,8 @@ declare_clippy_lint! {
/// ```rust /// ```rust
/// let x = 5; /// let x = 5;
/// match x { /// match x {
/// 1 ... 10 => println!("1 ... 10"), /// 1...10 => println!("1 ... 10"),
/// 5 ... 15 => println!("5 ... 15"), /// 5...15 => println!("5 ... 15"),
/// _ => (), /// _ => (),
/// } /// }
/// ``` /// ```
@ -152,7 +150,7 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// let x : Result(i32, &str) = Ok(3); /// let x: Result(i32, &str) = Ok(3);
/// match x { /// match x {
/// Ok(_) => println!("ok"), /// Ok(_) => println!("ok"),
/// Err(_) => panic!("err"), /// Err(_) => panic!("err"),
@ -243,19 +241,29 @@ fn check_single_match(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
} }
} }
fn check_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) { fn check_single_match_single_pattern(
cx: &LateContext<'_, '_>,
ex: &Expr,
arms: &[Arm],
expr: &Expr,
els: Option<&Expr>,
) {
if is_wild(&arms[1].pats[0]) { if is_wild(&arms[1].pats[0]) {
report_single_match_single_pattern(cx, ex, arms, expr, els); report_single_match_single_pattern(cx, ex, arms, expr, els);
} }
} }
fn report_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, els: Option<&Expr>) { fn report_single_match_single_pattern(
let lint = if els.is_some() { cx: &LateContext<'_, '_>,
SINGLE_MATCH_ELSE ex: &Expr,
} else { arms: &[Arm],
SINGLE_MATCH expr: &Expr,
}; els: Option<&Expr>,
let els_str = els.map_or(String::new(), |els| format!(" else {}", expr_block(cx, els, None, ".."))); ) {
let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
let els_str = els.map_or(String::new(), |els| {
format!(" else {}", expr_block(cx, els, None, ".."))
});
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
lint, lint,
@ -274,7 +282,14 @@ fn report_single_match_single_pattern(cx: &LateContext<'_, '_>, ex: &Expr, arms:
); );
} }
fn check_single_match_opt_like(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr, ty: Ty<'_>, els: Option<&Expr>) { fn check_single_match_opt_like(
cx: &LateContext<'_, '_>,
ex: &Expr,
arms: &[Arm],
expr: &Expr,
ty: Ty<'_>,
els: Option<&Expr>,
) {
// list of candidate Enums we know will never get any more members // list of candidate Enums we know will never get any more members
let candidates = &[ let candidates = &[
(&paths::COW, "Borrowed"), (&paths::COW, "Borrowed"),
@ -466,9 +481,12 @@ fn check_match_ref_pats(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr:
} }
fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr) { fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &Expr) {
if arms.len() == 2 && if arms.len() == 2
arms[0].pats.len() == 1 && arms[0].guard.is_none() && && arms[0].pats.len() == 1
arms[1].pats.len() == 1 && arms[1].guard.is_none() { && arms[0].guard.is_none()
&& arms[1].pats.len() == 1
&& arms[1].guard.is_none()
{
let arm_ref: Option<BindingAnnotation> = if is_none_arm(&arms[0]) { let arm_ref: Option<BindingAnnotation> = if is_none_arm(&arms[0]) {
is_ref_some_arm(&arms[1]) is_ref_some_arm(&arms[1])
} else if is_none_arm(&arms[1]) { } else if is_none_arm(&arms[1]) {
@ -477,7 +495,11 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
None None
}; };
if let Some(rb) = arm_ref { if let Some(rb) = arm_ref {
let suggestion = if rb == BindingAnnotation::Ref { "as_ref" } else { "as_mut" }; let suggestion = if rb == BindingAnnotation::Ref {
"as_ref"
} else {
"as_mut"
};
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
@ -485,7 +507,11 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
expr.span, expr.span,
&format!("use {}() instead", suggestion), &format!("use {}() instead", suggestion),
"try this", "try this",
format!("{}.{}()", snippet_with_applicability(cx, ex.span, "_", &mut applicability), suggestion), format!(
"{}.{}()",
snippet_with_applicability(cx, ex.span, "_", &mut applicability),
suggestion
),
applicability, applicability,
) )
} }
@ -493,22 +519,18 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
} }
/// Get all arms that are unbounded `PatRange`s. /// Get all arms that are unbounded `PatRange`s.
fn all_ranges<'a, 'tcx>( fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &'tcx [Arm]) -> Vec<SpannedRange<Constant>> {
cx: &LateContext<'a, 'tcx>,
arms: &'tcx [Arm],
) -> Vec<SpannedRange<Constant>> {
arms.iter() arms.iter()
.flat_map(|arm| { .flat_map(|arm| {
if let Arm { if let Arm {
ref pats, ref pats, guard: None, ..
guard: None,
..
} = *arm } = *arm
{ {
pats.iter() pats.iter()
} else { } else {
[].iter() [].iter()
}.filter_map(|pat| { }
.filter_map(|pat| {
if let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node { if let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node {
let lhs = constant(cx, cx.tables, lhs)?.0; let lhs = constant(cx, cx.tables, lhs)?.0;
let rhs = constant(cx, cx.tables, rhs)?.0; let rhs = constant(cx, cx.tables, rhs)?.0;
@ -516,12 +538,18 @@ fn all_ranges<'a, 'tcx>(
RangeEnd::Included => Bound::Included(rhs), RangeEnd::Included => Bound::Included(rhs),
RangeEnd::Excluded => Bound::Excluded(rhs), RangeEnd::Excluded => Bound::Excluded(rhs),
}; };
return Some(SpannedRange { span: pat.span, node: (lhs, rhs) }); return Some(SpannedRange {
span: pat.span,
node: (lhs, rhs),
});
} }
if let PatKind::Lit(ref value) = pat.node { if let PatKind::Lit(ref value) = pat.node {
let value = constant(cx, cx.tables, value)?.0; let value = constant(cx, cx.tables, value)?.0;
return Some(SpannedRange { span: pat.span, node: (value.clone(), Bound::Included(value)) }); return Some(SpannedRange {
span: pat.span,
node: (value.clone(), Bound::Included(value)),
});
} }
None None
@ -545,24 +573,15 @@ fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
ranges ranges
.iter() .iter()
.filter_map(|range| match range.node { .filter_map(|range| match range.node {
( (Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange {
Constant::Int(start),
Bound::Included(Constant::Int(end)),
) => Some(SpannedRange {
span: range.span, span: range.span,
node: (start, Bound::Included(end)), node: (start, Bound::Included(end)),
}), }),
( (Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange {
Constant::Int(start),
Bound::Excluded(Constant::Int(end)),
) => Some(SpannedRange {
span: range.span, span: range.span,
node: (start, Bound::Excluded(end)), node: (start, Bound::Excluded(end)),
}), }),
( (Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
Constant::Int(start),
Bound::Unbounded,
) => Some(SpannedRange {
span: range.span, span: range.span,
node: (start, Bound::Unbounded), node: (start, Bound::Unbounded),
}), }),
@ -608,7 +627,8 @@ fn is_ref_some_arm(arm: &Arm) -> Option<BindingAnnotation> {
} }
fn has_only_ref_pats(arms: &[Arm]) -> bool { fn has_only_ref_pats(arms: &[Arm]) -> bool {
let mapped = arms.iter() let mapped = arms
.iter()
.flat_map(|a| &a.pats) .flat_map(|a| &a.pats)
.map(|p| { .map(|p| {
match p.node { match p.node {
@ -682,8 +702,10 @@ where
for (a, b) in values.iter().zip(values.iter().skip(1)) { for (a, b) in values.iter().zip(values.iter().skip(1)) {
match (a, b) { match (a, b) {
(&Kind::Start(_, ra), &Kind::End(_, rb)) => if ra.node != rb.node { (&Kind::Start(_, ra), &Kind::End(_, rb)) => {
if ra.node != rb.node {
return Some((ra, rb)); return Some((ra, rb));
}
}, },
(&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (), (&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
_ => return Some((a.range(), b.range())), _ => return Some((a.range(), b.range())),

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::{Expr, ExprKind}; use crate::rustc::hir::{Expr, ExprKind};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};

View file

@ -7,10 +7,9 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::{Expr, ExprKind};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::{Expr, ExprKind};
use crate::utils::{match_def_path, opt_def_id, paths, span_lint}; use crate::utils::{match_def_path, opt_def_id, paths, span_lint};
/// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is /// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::{Expr, ExprKind, MutMutable, QPath}; use crate::rustc::hir::{Expr, ExprKind, MutMutable, QPath};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};

View file

@ -7,11 +7,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::hir::def::Def; use crate::rustc::hir::def::Def;
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, Lint, LintArray, LintContext, LintPass}; use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, Lint, LintArray, LintContext, LintPass};
use crate::rustc::ty::{self, Ty, TyKind, Predicate}; use crate::rustc::ty::{self, Predicate, Ty, TyKind};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::syntax::ast; use crate::syntax::ast;
@ -23,7 +22,7 @@ use crate::utils::{
get_arg_name, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, is_self, is_self_ty, get_arg_name, get_trait_def_id, implements_trait, in_macro, is_copy, is_expn_of, is_self, is_self_ty,
iter_input_pats, last_path_segment, match_def_path, match_path, match_qpath, match_trait_method, match_type, iter_input_pats, last_path_segment, match_def_path, match_path, match_qpath, match_trait_method, match_type,
match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys, single_segment_path, snippet, match_var, method_calls, method_chain_args, remove_blocks, return_ty, same_tys, single_segment_path, snippet,
snippet_with_macro_callsite, snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_sugg, span_lint_and_then,
span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq, span_note_and_lint, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
}; };
use if_chain::if_chain; use if_chain::if_chain;
@ -95,7 +94,9 @@ declare_clippy_lint! {
/// ```rust /// ```rust
/// struct X; /// struct X;
/// impl X { /// impl X {
/// fn add(&self, other: &X) -> X { .. } /// fn add(&self, other: &X) -> X {
/// ..
/// }
/// } /// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
@ -124,14 +125,15 @@ declare_clippy_lint! {
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// impl X { /// impl X {
/// fn as_str(self) -> &str { .. } /// fn as_str(self) -> &str {
/// ..
/// }
/// } /// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub WRONG_SELF_CONVENTION, pub WRONG_SELF_CONVENTION,
style, style,
"defining a method named with an established prefix (like \"into_\") that takes \ "defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
`self` with the wrong convention"
} }
/// **What it does:** This is the same as /// **What it does:** This is the same as
@ -146,14 +148,15 @@ declare_clippy_lint! {
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// impl X { /// impl X {
/// pub fn as_str(self) -> &str { .. } /// pub fn as_str(self) -> &str {
/// ..
/// }
/// } /// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub WRONG_PUB_SELF_CONVENTION, pub WRONG_PUB_SELF_CONVENTION,
restriction, restriction,
"defining a public method named with an established prefix (like \"into_\") that takes \ "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
`self` with the wrong convention"
} }
/// **What it does:** Checks for usage of `ok().expect(..)`. /// **What it does:** Checks for usage of `ok().expect(..)`.
@ -170,8 +173,7 @@ declare_clippy_lint! {
declare_clippy_lint! { declare_clippy_lint! {
pub OK_EXPECT, pub OK_EXPECT,
style, style,
"using `ok().expect()`, which gives worse error messages than \ "using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
calling `expect` directly on the Result"
} }
/// **What it does:** Checks for usage of `_.map(_).unwrap_or(_)`. /// **What it does:** Checks for usage of `_.map(_).unwrap_or(_)`.
@ -186,9 +188,9 @@ declare_clippy_lint! {
/// x.map(|a| a + 1).unwrap_or(0) /// x.map(|a| a + 1).unwrap_or(0)
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub OPTION_MAP_UNWRAP_OR, pub OPTION_MAP_UNWRAP_OR,
pedantic, pedantic,
"using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \ "using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \
`map_or(a, f)`" `map_or(a, f)`"
} }
@ -206,8 +208,7 @@ declare_clippy_lint! {
declare_clippy_lint! { declare_clippy_lint! {
pub OPTION_MAP_UNWRAP_OR_ELSE, pub OPTION_MAP_UNWRAP_OR_ELSE,
pedantic, pedantic,
"using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \ "using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`"
`map_or_else(g, f)`"
} }
/// **What it does:** Checks for usage of `result.map(_).unwrap_or_else(_)`. /// **What it does:** Checks for usage of `result.map(_).unwrap_or_else(_)`.
@ -224,8 +225,7 @@ declare_clippy_lint! {
declare_clippy_lint! { declare_clippy_lint! {
pub RESULT_MAP_UNWRAP_OR_ELSE, pub RESULT_MAP_UNWRAP_OR_ELSE,
pedantic, pedantic,
"using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \ "using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.ok().map_or_else(g, f)`"
`.ok().map_or_else(g, f)`"
} }
/// **What it does:** Checks for usage of `_.map_or(None, _)`. /// **What it does:** Checks for usage of `_.map_or(None, _)`.
@ -242,8 +242,7 @@ declare_clippy_lint! {
declare_clippy_lint! { declare_clippy_lint! {
pub OPTION_MAP_OR_NONE, pub OPTION_MAP_OR_NONE,
style, style,
"using `Option.map_or(None, f)`, which is more succinctly expressed as \ "using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`"
`and_then(f)`"
} }
/// **What it does:** Checks for usage of `_.filter(_).next()`. /// **What it does:** Checks for usage of `_.filter(_).next()`.
@ -277,8 +276,7 @@ declare_clippy_lint! {
declare_clippy_lint! { declare_clippy_lint! {
pub MAP_FLATTEN, pub MAP_FLATTEN,
pedantic, pedantic,
"using combinations of `flatten` and `map` which can usually be written as a \ "using combinations of `flatten` and `map` which can usually be written as a single method call"
single method call"
} }
/// **What it does:** Checks for usage of `_.filter(_).map(_)`, /// **What it does:** Checks for usage of `_.filter(_).map(_)`,
@ -297,8 +295,7 @@ declare_clippy_lint! {
declare_clippy_lint! { declare_clippy_lint! {
pub FILTER_MAP, pub FILTER_MAP,
pedantic, pedantic,
"using combinations of `filter`, `map`, `filter_map` and `flat_map` which can \ "using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call"
usually be written as a single method call"
} }
/// **What it does:** Checks for an iterator search (such as `find()`, /// **What it does:** Checks for an iterator search (such as `find()`,
@ -316,8 +313,7 @@ declare_clippy_lint! {
declare_clippy_lint! { declare_clippy_lint! {
pub SEARCH_IS_SOME, pub SEARCH_IS_SOME,
complexity, complexity,
"using an iterator search followed by `is_some()`, which is more succinctly \ "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`"
expressed as a call to `any()`"
} }
/// **What it does:** Checks for usage of `.chars().next()` on a `str` to check /// **What it does:** Checks for usage of `.chars().next()` on a `str` to check
@ -440,7 +436,7 @@ declare_clippy_lint! {
/// let x = vec![1]; /// let x = vec![1];
/// let y = &&x; /// let y = &&x;
/// let z = y.clone(); /// let z = y.clone();
/// println!("{:p} {:p}",*y, z); // prints out the same pointer /// println!("{:p} {:p}", *y, z); // prints out the same pointer
/// } /// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
@ -482,8 +478,7 @@ declare_clippy_lint! {
declare_clippy_lint! { declare_clippy_lint! {
pub SINGLE_CHAR_PATTERN, pub SINGLE_CHAR_PATTERN,
perf, perf,
"using a single-character str where a char could be used, e.g. \ "using a single-character str where a char could be used, e.g. `_.split(\"x\")`"
`_.split(\"x\")`"
} }
/// **What it does:** Checks for getting the inner pointer of a temporary /// **What it does:** Checks for getting the inner pointer of a temporary
@ -635,13 +630,13 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// let s = [1,2,3,4,5]; /// let s = [1, 2, 3, 4, 5];
/// let s2 : Vec<isize> = s[..].iter().cloned().collect(); /// let s2: Vec<isize> = s[..].iter().cloned().collect();
/// ``` /// ```
/// The better use would be: /// The better use would be:
/// ```rust /// ```rust
/// let s = [1,2,3,4,5]; /// let s = [1, 2, 3, 4, 5];
/// let s2 : Vec<isize> = s.to_vec(); /// let s2: Vec<isize> = s.to_vec();
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub ITER_CLONED_COLLECT, pub ITER_CLONED_COLLECT,
@ -676,12 +671,12 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// let x: &[i32] = &[1,2,3,4,5]; /// let x: &[i32] = &[1, 2, 3, 4, 5];
/// do_stuff(x.as_ref()); /// do_stuff(x.as_ref());
/// ``` /// ```
/// The correct use would be: /// The correct use would be:
/// ```rust /// ```rust
/// let x: &[i32] = &[1,2,3,4,5]; /// let x: &[i32] = &[1, 2, 3, 4, 5];
/// do_stuff(x); /// do_stuff(x);
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
@ -690,7 +685,6 @@ declare_clippy_lint! {
"using `as_ref` where the types before and after the call are the same" "using `as_ref` where the types before and after the call are the same"
} }
/// **What it does:** Checks for using `fold` when a more succinct alternative exists. /// **What it does:** Checks for using `fold` when a more succinct alternative exists.
/// Specifically, this checks for `fold`s which could be replaced by `any`, `all`, /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
/// `sum` or `product`. /// `sum` or `product`.
@ -714,7 +708,6 @@ declare_clippy_lint! {
"using `fold` when a more succinct alternative exists" "using `fold` when a more succinct alternative exists"
} }
/// **What it does:** Checks for `filter_map` calls which could be replaced by `filter` or `map`. /// **What it does:** Checks for `filter_map` calls which could be replaced by `filter` or `map`.
/// More specifically it checks if the closure provided is only performing one of the /// More specifically it checks if the closure provided is only performing one of the
/// filter or map operations and suggests the appropriate option. /// filter or map operations and suggests the appropriate option.
@ -870,12 +863,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
["as_mut", ..] => lint_asref(cx, expr, "as_mut", arg_lists[0]), ["as_mut", ..] => lint_asref(cx, expr, "as_mut", arg_lists[0]),
["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0]), ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0]),
["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]), ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]),
_ => {} _ => {},
} }
match expr.node { match expr.node {
hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args) => { hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args) => {
lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
@ -886,10 +878,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} }
match self_ty.sty { match self_ty.sty {
ty::Ref(_, ty, _) if ty.sty == ty::Str => for &(method, pos) in &PATTERN_METHODS { ty::Ref(_, ty, _) if ty.sty == ty::Str => {
for &(method, pos) in &PATTERN_METHODS {
if method_call.ident.name == method && args.len() > pos { if method_call.ident.name == method && args.len() > pos {
lint_single_char_pattern(cx, expr, &args[pos]); lint_single_char_pattern(cx, expr, &args[pos]);
} }
}
}, },
ty::Ref(..) if method_call.ident.name == "into_iter" => { ty::Ref(..) if method_call.ident.name == "into_iter" => {
lint_into_iter(cx, expr, self_ty, *method_span); lint_into_iter(cx, expr, self_ty, *method_span);
@ -897,7 +891,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
_ => (), _ => (),
} }
}, },
hir::ExprKind::Binary(op, ref lhs, ref rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { hir::ExprKind::Binary(op, ref lhs, ref rhs)
if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne =>
{
let mut info = BinaryExprInfo { let mut info = BinaryExprInfo {
expr, expr,
chain: lhs, chain: lhs,
@ -905,7 +901,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
eq: op.node == hir::BinOpKind::Eq, eq: op.node == hir::BinOpKind::Eq,
}; };
lint_binary_expr_with_method_call(cx, &mut info); lint_binary_expr_with_method_call(cx, &mut info);
}, }
_ => (), _ => (),
} }
} }
@ -963,7 +959,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
.join(" or "))); .join(" or ")));
} }
// Only check the first convention to match (CONVENTIONS should be listed from most to least specific) // Only check the first convention to match (CONVENTIONS should be listed from most to least
// specific)
break; break;
} }
} }
@ -975,12 +972,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
// walk the return type and check for Self (this does not check associated types) // walk the return type and check for Self (this does not check associated types)
for inner_type in ret_ty.walk() { for inner_type in ret_ty.walk() {
if same_tys(cx, ty, inner_type) { return; } if same_tys(cx, ty, inner_type) {
return;
}
} }
// if return type is impl trait, check the associated types // if return type is impl trait, check the associated types
if let TyKind::Opaque(def_id, _) = ret_ty.sty { if let TyKind::Opaque(def_id, _) = ret_ty.sty {
// one of the associated types must be Self // one of the associated types must be Self
for predicate in &cx.tcx.predicates_of(def_id).predicates { for predicate in &cx.tcx.predicates_of(def_id).predicates {
match predicate { match predicate {
@ -990,7 +988,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
let associated_type_is_self_type = same_tys(cx, ty, associated_type); let associated_type_is_self_type = same_tys(cx, ty, associated_type);
// if the associated type is self, early return and do not trigger lint // if the associated type is self, early return and do not trigger lint
if associated_type_is_self_type { return; } if associated_type_is_self_type {
return;
}
}, },
(_, _) => {}, (_, _) => {},
} }
@ -998,10 +998,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} }
if name == "new" && !same_tys(cx, ret_ty, ty) { if name == "new" && !same_tys(cx, ret_ty, ty) {
span_lint(cx, span_lint(
cx,
NEW_RET_NO_SELF, NEW_RET_NO_SELF,
implitem.span, implitem.span,
"methods called `new` usually return `Self`"); "methods called `new` usually return `Self`",
);
} }
} }
} }
@ -1043,7 +1045,10 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa
span, span,
&format!("use of `{}` followed by a call to `{}`", name, path), &format!("use of `{}` followed by a call to `{}`", name, path),
"try this", "try this",
format!("{}.unwrap_or_default()", snippet_with_applicability(cx, self_expr.span, "_", &mut applicability)), format!(
"{}.unwrap_or_default()",
snippet_with_applicability(cx, self_expr.span, "_", &mut applicability)
),
applicability, applicability,
); );
return true; return true;
@ -1123,12 +1128,28 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa
hir::ExprKind::Call(ref fun, ref or_args) => { hir::ExprKind::Call(ref fun, ref or_args) => {
let or_has_args = !or_args.is_empty(); let or_has_args = !or_args.is_empty();
if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) {
check_general_case(cx, name, method_span, fun.span, &args[0], &args[1], or_has_args, expr.span); check_general_case(
cx,
name,
method_span,
fun.span,
&args[0],
&args[1],
or_has_args,
expr.span,
);
} }
}, },
hir::ExprKind::MethodCall(_, span, ref or_args) => { hir::ExprKind::MethodCall(_, span, ref or_args) => check_general_case(
check_general_case(cx, name, method_span, span, &args[0], &args[1], !or_args.is_empty(), expr.span) cx,
}, name,
method_span,
span,
&args[0],
&args[1],
!or_args.is_empty(),
expr.span,
),
_ => {}, _ => {},
} }
} }
@ -1138,11 +1159,12 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa
fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) { fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Span, name: &str, args: &[hir::Expr]) {
fn extract_format_args(arg: &hir::Expr) -> Option<&hir::HirVec<hir::Expr>> { fn extract_format_args(arg: &hir::Expr) -> Option<&hir::HirVec<hir::Expr>> {
let arg = match &arg.node { let arg = match &arg.node {
hir::ExprKind::AddrOf(_, expr)=> expr, hir::ExprKind::AddrOf(_, expr) => expr,
hir::ExprKind::MethodCall(method_name, _, args) hir::ExprKind::MethodCall(method_name, _, args)
if method_name.ident.name == "as_str" || if method_name.ident.name == "as_str" || method_name.ident.name == "as_ref" =>
method_name.ident.name == "as_ref" {
=> &args[0], &args[0]
},
_ => arg, _ => arg,
}; };
@ -1165,7 +1187,8 @@ fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span:
if let hir::ExprKind::AddrOf(_, ref format_arg) = a.node { if let hir::ExprKind::AddrOf(_, ref format_arg) = a.node {
if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.node { if let hir::ExprKind::Match(ref format_arg_expr, _, _) = format_arg.node {
if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.node { if let hir::ExprKind::Tup(ref format_arg_expr_tup) = format_arg_expr.node {
return snippet_with_applicability(cx, format_arg_expr_tup[0].span, "..", applicability).into_owned(); return snippet_with_applicability(cx, format_arg_expr_tup[0].span, "..", applicability)
.into_owned();
} }
} }
}; };
@ -1212,7 +1235,11 @@ fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span:
return; return;
} }
let closure = if match_type(cx, self_type, &paths::OPTION) { "||" } else { "|_|" }; let closure = if match_type(cx, self_type, &paths::OPTION) {
"||"
} else {
"|_|"
};
let span_replace_word = method_span.with_hi(span.hi()); let span_replace_word = method_span.with_hi(span.hi());
if let Some(format_args) = extract_format_args(arg) { if let Some(format_args) = extract_format_args(arg) {
@ -1272,7 +1299,8 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
expr.span, expr.span,
"using `clone` on a double-reference; \ "using `clone` on a double-reference; \
this will copy the reference instead of cloning the inner type", this will copy the reference instead of cloning the inner type",
|db| if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { |db| {
if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
let mut ty = innermost; let mut ty = innermost;
let mut n = 0; let mut n = 0;
while let ty::Ref(_, inner, _) = ty.sty { while let ty::Ref(_, inner, _) = ty.sty {
@ -1294,6 +1322,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
explicit, explicit,
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
); );
}
}, },
); );
return; // don't report clone_on_copy return; // don't report clone_on_copy
@ -1312,7 +1341,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
// (*x).func() is useless, x.clone().func() can work in case func borrows mutably // (*x).func() is useless, x.clone().func() can work in case func borrows mutably
hir::ExprKind::MethodCall(..) => return, hir::ExprKind::MethodCall(..) => return,
_ => {}, _ => {},
} },
hir::Node::Stmt(stmt) => { hir::Node::Stmt(stmt) => {
if let hir::StmtKind::Decl(ref decl, _) = stmt.node { if let hir::StmtKind::Decl(ref decl, _) = stmt.node {
if let hir::DeclKind::Local(ref loc) = decl.node { if let hir::DeclKind::Local(ref loc) = decl.node {
@ -1334,12 +1363,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
} }
span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |db| { span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |db| {
if let Some((text, snip)) = snip { if let Some((text, snip)) = snip {
db.span_suggestion_with_applicability( db.span_suggestion_with_applicability(expr.span, text, snip, Applicability::Unspecified);
expr.span,
text,
snip,
Applicability::Unspecified,
);
} }
}); });
} }
@ -1365,13 +1389,17 @@ fn lint_clone_on_ref_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::
expr.span, expr.span,
"using '.clone()' on a ref-counted pointer", "using '.clone()' on a ref-counted pointer",
"try this", "try this",
format!("{}::<{}>::clone(&{})", caller_type, subst.type_at(0), snippet(cx, arg.span, "_")), format!(
"{}::<{}>::clone(&{})",
caller_type,
subst.type_at(0),
snippet(cx, arg.span, "_")
),
Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak Applicability::Unspecified, // Sometimes unnecessary ::<_> after Rc/Arc/Weak
); );
} }
} }
fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) { fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
let arg = &args[1]; let arg = &args[1];
if let Some(arglists) = method_chain_args(arg, &["chars"]) { if let Some(arglists) = method_chain_args(arg, &["chars"]) {
@ -1451,8 +1479,8 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args:
fold_args: &[hir::Expr], fold_args: &[hir::Expr],
op: hir::BinOpKind, op: hir::BinOpKind,
replacement_method_name: &str, replacement_method_name: &str,
replacement_has_args: bool) { replacement_has_args: bool,
) {
if_chain! { if_chain! {
// Extract the body of the closure passed to fold // Extract the body of the closure passed to fold
if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].node; if let hir::ExprKind::Closure(_, _, body_id, _, _) = fold_args[2].node;
@ -1509,29 +1537,21 @@ fn lint_unnecessary_fold(cx: &LateContext<'_, '_>, expr: &hir::Expr, fold_args:
return; return;
} }
assert!(fold_args.len() == 3, assert!(
"Expected fold_args to have three entries - the receiver, the initial value and the closure"); fold_args.len() == 3,
"Expected fold_args to have three entries - the receiver, the initial value and the closure"
);
// Check if the first argument to .fold is a suitable literal // Check if the first argument to .fold is a suitable literal
match fold_args[1].node { match fold_args[1].node {
hir::ExprKind::Lit(ref lit) => { hir::ExprKind::Lit(ref lit) => match lit.node {
match lit.node { ast::LitKind::Bool(false) => check_fold_with_op(cx, fold_args, hir::BinOpKind::Or, "any", true),
ast::LitKind::Bool(false) => check_fold_with_op( ast::LitKind::Bool(true) => check_fold_with_op(cx, fold_args, hir::BinOpKind::And, "all", true),
cx, fold_args, hir::BinOpKind::Or, "any", true ast::LitKind::Int(0, _) => check_fold_with_op(cx, fold_args, hir::BinOpKind::Add, "sum", false),
), ast::LitKind::Int(1, _) => check_fold_with_op(cx, fold_args, hir::BinOpKind::Mul, "product", false),
ast::LitKind::Bool(true) => check_fold_with_op( _ => return,
cx, fold_args, hir::BinOpKind::And, "all", true },
), _ => return,
ast::LitKind::Int(0, _) => check_fold_with_op(
cx, fold_args, hir::BinOpKind::Add, "sum", false
),
ast::LitKind::Int(1, _) => check_fold_with_op(
cx, fold_args, hir::BinOpKind::Mul, "product", false
),
_ => return
}
}
_ => return
}; };
} }
@ -1553,8 +1573,7 @@ fn lint_iter_nth(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::E
expr.span, expr.span,
&format!( &format!(
"called `.iter{0}().nth()` on a {1}. Calling `.get{0}()` is both faster and more readable", "called `.iter{0}().nth()` on a {1}. Calling `.get{0}()` is both faster and more readable",
mut_str, mut_str, caller_type
caller_type
), ),
); );
} }
@ -1590,15 +1609,20 @@ fn lint_get_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, get_args: &[hir::
}; };
let mut_str = if is_mut { "_mut" } else { "" }; let mut_str = if is_mut { "_mut" } else { "" };
let borrow_str = if !needs_ref { "" } else if is_mut { "&mut " } else { "&" }; let borrow_str = if !needs_ref {
""
} else if is_mut {
"&mut "
} else {
"&"
};
span_lint_and_sugg( span_lint_and_sugg(
cx, cx,
GET_UNWRAP, GET_UNWRAP,
expr.span, expr.span,
&format!( &format!(
"called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise", "called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
mut_str, mut_str, caller_type
caller_type
), ),
"try this", "try this",
format!( format!(
@ -1645,10 +1669,12 @@ fn derefs_to_slice(cx: &LateContext<'_, '_>, expr: &hir::Expr, ty: Ty<'_>) -> Op
match ty.sty { match ty.sty {
ty::Slice(_) => sugg::Sugg::hir_opt(cx, expr), ty::Slice(_) => sugg::Sugg::hir_opt(cx, expr),
ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => sugg::Sugg::hir_opt(cx, expr), ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => sugg::Sugg::hir_opt(cx, expr),
ty::Ref(_, inner, _) => if may_slice(cx, inner) { ty::Ref(_, inner, _) => {
if may_slice(cx, inner) {
sugg::Sugg::hir_opt(cx, expr) sugg::Sugg::hir_opt(cx, expr)
} else { } else {
None None
}
}, },
_ => None, _ => None,
} }
@ -1676,8 +1702,7 @@ fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr, unwrap_args: &[hir::E
"used unwrap() on {} value. If you don't want to handle the {} case gracefully, consider \ "used unwrap() on {} value. If you don't want to handle the {} case gracefully, consider \
using expect() to provide a better panic \ using expect() to provide a better panic \
message", message",
kind, kind, none_value
none_value
), ),
); );
} }
@ -1711,11 +1736,7 @@ fn lint_map_unwrap_or(cx: &LateContext<'_, '_>, expr: &hir::Expr, map_args: &[hi
// lint message // lint message
// comparing the snippet from source to raw text ("None") below is safe // comparing the snippet from source to raw text ("None") below is safe
// because we already have checked the type. // because we already have checked the type.
let arg = if unwrap_snippet == "None" { let arg = if unwrap_snippet == "None" { "None" } else { "a" };
"None"
} else {
"a"
};
let suggest = if unwrap_snippet == "None" { let suggest = if unwrap_snippet == "None" {
"and_then(f)" "and_then(f)"
} else { } else {
@ -1724,8 +1745,7 @@ fn lint_map_unwrap_or(cx: &LateContext<'_, '_>, expr: &hir::Expr, map_args: &[hi
let msg = &format!( let msg = &format!(
"called `map(f).unwrap_or({})` on an Option value. \ "called `map(f).unwrap_or({})` on an Option value. \
This can be done more directly by calling `{}` instead", This can be done more directly by calling `{}` instead",
arg, arg, suggest
suggest
); );
// lint, with note if neither arg is > 1 line and both map() and // lint, with note if neither arg is > 1 line and both map() and
// unwrap_or() have the same span // unwrap_or() have the same span
@ -1739,9 +1759,7 @@ fn lint_map_unwrap_or(cx: &LateContext<'_, '_>, expr: &hir::Expr, map_args: &[hi
}; };
let note = format!( let note = format!(
"replace `map({}).unwrap_or({})` with `{}`", "replace `map({}).unwrap_or({})` with `{}`",
map_snippet, map_snippet, unwrap_snippet, suggest
unwrap_snippet,
suggest
); );
span_note_and_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg, expr.span, &note); span_note_and_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg, expr.span, &note);
} else if same_span && multiline { } else if same_span && multiline {
@ -1751,11 +1769,7 @@ fn lint_map_unwrap_or(cx: &LateContext<'_, '_>, expr: &hir::Expr, map_args: &[hi
} }
/// lint use of `map().flatten()` for `Iterators` /// lint use of `map().flatten()` for `Iterators`
fn lint_map_flatten<'a, 'tcx>( fn lint_map_flatten<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_args: &'tcx [hir::Expr]) {
cx: &LateContext<'a, 'tcx>,
expr: &'tcx hir::Expr,
map_args: &'tcx [hir::Expr],
) {
// lint if caller of `.map().flatten()` is an Iterator // lint if caller of `.map().flatten()` is an Iterator
if match_trait_method(cx, expr, &paths::ITERATOR) { if match_trait_method(cx, expr, &paths::ITERATOR) {
let msg = "called `map(..).flatten()` on an `Iterator`. \ let msg = "called `map(..).flatten()` on an `Iterator`. \
@ -1971,7 +1985,10 @@ fn lint_search_is_some<'a, 'tcx>(
expr.span, expr.span,
&msg, &msg,
expr.span, expr.span,
&format!("replace `{0}({1}).is_some()` with `any({1})`", search_method, search_snippet), &format!(
"replace `{0}({1}).is_some()` with `any({1})`",
search_method, search_snippet
),
); );
} else { } else {
span_lint(cx, SEARCH_IS_SOME, expr.span, &msg); span_lint(cx, SEARCH_IS_SOME, expr.span, &msg);
@ -1998,7 +2015,7 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_, '_>, info: &mut Binary
return; return;
} }
} }
} };
} }
lint_with_both_lhs_and_rhs!(lint_chars_next_cmp, cx, info); lint_with_both_lhs_and_rhs!(lint_chars_next_cmp, cx, info);
@ -2163,7 +2180,10 @@ fn lint_asref(cx: &LateContext<'_, '_>, expr: &hir::Expr, call_name: &str, as_re
} }
} }
fn ty_has_iter_method(cx: &LateContext<'_, '_>, self_ref_ty: ty::Ty<'_>) -> Option<(&'static Lint, &'static str, &'static str)> { fn ty_has_iter_method(
cx: &LateContext<'_, '_>,
self_ref_ty: ty::Ty<'_>,
) -> Option<(&'static Lint, &'static str, &'static str)> {
// FIXME: instead of this hard-coded list, we should check if `<adt>::iter` // FIXME: instead of this hard-coded list, we should check if `<adt>::iter`
// exists and has the desired signature. Unfortunately FnCtxt is not exported // exists and has the desired signature. Unfortunately FnCtxt is not exported
// so we can't use its `lookup_method` method. // so we can't use its `lookup_method` method.
@ -2201,7 +2221,7 @@ fn ty_has_iter_method(cx: &LateContext<'_, '_>, self_ref_ty: ty::Ty<'_>) -> Opti
for (lint, path) in &INTO_ITER_COLLECTIONS { for (lint, path) in &INTO_ITER_COLLECTIONS {
if match_def_path(cx.tcx, def_id, path) { if match_def_path(cx.tcx, def_id, path) {
return Some((lint, path.last().unwrap(), method_name)) return Some((lint, path.last().unwrap(), method_name));
} }
} }
None None
@ -2218,8 +2238,7 @@ fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: ty::T
method_span, method_span,
&format!( &format!(
"this .into_iter() call is equivalent to .{}() and will not move the {}", "this .into_iter() call is equivalent to .{}() and will not move the {}",
method_name, method_name, kind,
kind,
), ),
"call directly", "call directly",
method_name.to_string(), method_name.to_string(),
@ -2228,7 +2247,6 @@ fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: ty::T
} }
} }
/// Given a `Result<T, E>` type, return its error type (`E`). /// Given a `Result<T, E>` type, return its error type (`E`).
fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option<Ty<'a>> { fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option<Ty<'a>> {
if let ty::Adt(_, substs) = ty.sty { if let ty::Adt(_, substs) = ty.sty {
@ -2321,7 +2339,6 @@ const PATTERN_METHODS: [(&str, usize); 17] = [
("trim_right_matches", 1), ("trim_right_matches", 1),
]; ];
#[derive(Clone, Copy, PartialEq, Debug)] #[derive(Clone, Copy, PartialEq, Debug)]
enum SelfKind { enum SelfKind {
Value, Value,
@ -2397,22 +2414,27 @@ fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Gener
single_segment_ty(ty).map_or(false, |seg| { single_segment_ty(ty).map_or(false, |seg| {
generics.params.iter().any(|param| match param.kind { generics.params.iter().any(|param| match param.kind {
hir::GenericParamKind::Type { .. } => { hir::GenericParamKind::Type { .. } => {
param.name.ident().name == seg.ident.name && param.bounds.iter().any(|bound| { param.name.ident().name == seg.ident.name
&& param.bounds.iter().any(|bound| {
if let hir::GenericBound::Trait(ref ptr, ..) = *bound { if let hir::GenericBound::Trait(ref ptr, ..) = *bound {
let path = &ptr.trait_ref.path; let path = &ptr.trait_ref.path;
match_path(path, name) && path.segments.last().map_or(false, |s| { match_path(path, name)
&& path.segments.last().map_or(false, |s| {
if let Some(ref params) = s.args { if let Some(ref params) = s.args {
if params.parenthesized { if params.parenthesized {
false false
} else { } else {
// FIXME(flip1995): messy, improve if there is a better option // FIXME(flip1995): messy, improve if there is a better option
// in the compiler // in the compiler
let types: Vec<_> = params.args.iter().filter_map(|arg| match arg { let types: Vec<_> = params
.args
.iter()
.filter_map(|arg| match arg {
hir::GenericArg::Type(ty) => Some(ty), hir::GenericArg::Type(ty) => Some(ty),
_ => None, _ => None,
}).collect(); })
types.len() == 1 .collect();
&& (is_self_ty(&types[0]) || is_ty(&*types[0], self_ty)) types.len() == 1 && (is_self_ty(&types[0]) || is_ty(&*types[0], self_ty))
} }
} else { } else {
false false

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::hir::def::Def; use crate::rustc::hir::def::Def;
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};

View file

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::consts::{constant_simple, Constant}; use crate::consts::{constant_simple, Constant};
use crate::utils::{match_def_path, opt_def_id, paths, span_lint};
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{match_def_path, opt_def_id, paths, span_lint};
use std::cmp::Ordering; use std::cmp::Ordering;
/// **What it does:** Checks for expressions where `std::cmp::min` and `max` are /// **What it does:** Checks for expressions where `std::cmp::min` and `max` are

View file

@ -7,23 +7,24 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::reexport::*;
use matches::matches;
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::FnKind;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty;
use crate::syntax::source_map::{ExpnFormat, Span};
use crate::utils::{get_item_name, get_parent_expr, implements_trait, in_constant, in_macro, is_integer_literal,
iter_input_pats, last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint,
span_lint_and_then, walk_ptrs_ty, SpanlessEq};
use crate::utils::sugg::Sugg;
use crate::syntax::ast::LitKind;
use crate::consts::{constant, Constant}; use crate::consts::{constant, Constant};
use crate::reexport::*;
use crate::rustc::hir::intravisit::FnKind;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::syntax::ast::LitKind;
use crate::syntax::source_map::{ExpnFormat, Span};
use crate::utils::sugg::Sugg;
use crate::utils::{
get_item_name, get_parent_expr, implements_trait, in_constant, in_macro, is_integer_literal, iter_input_pats,
last_path_segment, match_qpath, match_trait_method, paths, snippet, span_lint, span_lint_and_then, walk_ptrs_ty,
SpanlessEq,
};
use if_chain::if_chain;
use matches::matches;
/// **What it does:** Checks for function arguments and let bindings denoted as /// **What it does:** Checks for function arguments and let bindings denoted as
/// `ref`. /// `ref`.
@ -43,7 +44,9 @@ use crate::rustc_errors::Applicability;
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// fn foo(ref x: u8) -> bool { .. } /// fn foo(ref x: u8) -> bool {
/// ..
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub TOPLEVEL_REF_ARG, pub TOPLEVEL_REF_ARG,
@ -266,8 +269,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} }
for arg in iter_input_pats(decl, body) { for arg in iter_input_pats(decl, body) {
match arg.pat.node { match arg.pat.node {
PatKind::Binding(BindingAnnotation::Ref, _, _, _) | PatKind::Binding(BindingAnnotation::Ref, _, _, _)
PatKind::Binding(BindingAnnotation::RefMut, _, _, _) => { | PatKind::Binding(BindingAnnotation::RefMut, _, _, _) => {
span_lint( span_lint(
cx, cx,
TOPLEVEL_REF_ARG, TOPLEVEL_REF_ARG,
@ -372,7 +375,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} }
if let Some(name) = get_item_name(cx, expr) { if let Some(name) = get_item_name(cx, expr) {
let name = name.as_str(); let name = name.as_str();
if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") if name == "eq"
|| name == "ne"
|| name == "is_nan"
|| name.starts_with("eq_")
|| name.ends_with("_eq") || name.ends_with("_eq")
{ {
return; return;
@ -451,7 +457,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
cx, cx,
REDUNDANT_PATTERN, REDUNDANT_PATTERN,
pat.span, pat.span,
&format!("the `{} @ _` pattern can be written as just `{}`", ident.name, ident.name), &format!(
"the `{} @ _` pattern can be written as just `{}`",
ident.name, ident.name
),
); );
} }
} }
@ -502,7 +511,8 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr, other: &Expr) {
return; return;
} }
}, },
ExprKind::Call(ref path, ref v) if v.len() == 1 => if let ExprKind::Path(ref path) = path.node { ExprKind::Call(ref path, ref v) if v.len() == 1 => {
if let ExprKind::Path(ref path) = path.node {
if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) { if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) {
(cx.tables.expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, "..")) (cx.tables.expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
} else { } else {
@ -510,6 +520,7 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr, other: &Expr) {
} }
} else { } else {
return; return;
}
}, },
_ => return, _ => return,
}; };
@ -520,18 +531,15 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr, other: &Expr) {
None => return, None => return,
}; };
let deref_arg_impl_partial_eq_other = arg_ty let deref_arg_impl_partial_eq_other = arg_ty.builtin_deref(true).map_or(false, |tam| {
.builtin_deref(true) implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty.into()])
.map_or(false, |tam| implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty.into()])); });
let arg_impl_partial_eq_deref_other = other_ty let arg_impl_partial_eq_deref_other = other_ty.builtin_deref(true).map_or(false, |tam| {
.builtin_deref(true) implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty.into()])
.map_or(false, |tam| implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty.into()])); });
let arg_impl_partial_eq_other = implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty.into()]); let arg_impl_partial_eq_other = implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty.into()]);
if !deref_arg_impl_partial_eq_other if !deref_arg_impl_partial_eq_other && !arg_impl_partial_eq_deref_other && !arg_impl_partial_eq_other {
&& !arg_impl_partial_eq_deref_other
&& !arg_impl_partial_eq_other
{
return; return;
} }

View file

@ -7,17 +7,16 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, LintContext, in_external_macro};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::FxHashMap; use crate::rustc_data_structures::fx::FxHashMap;
use if_chain::if_chain; use crate::rustc_errors::Applicability;
use std::char;
use crate::syntax::ast::*; use crate::syntax::ast::*;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::syntax::visit::{FnKind, Visitor, walk_expr}; use crate::syntax::visit::{walk_expr, FnKind, Visitor};
use crate::utils::{constants, snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_then}; use crate::utils::{constants, snippet, snippet_opt, span_help_and_lint, span_lint, span_lint_and_then};
use crate::rustc_errors::Applicability; use if_chain::if_chain;
use std::char;
/// **What it does:** Checks for structure field patterns bound to wildcards. /// **What it does:** Checks for structure field patterns bound to wildcards.
/// ///
@ -206,9 +205,7 @@ struct ReturnVisitor {
impl ReturnVisitor { impl ReturnVisitor {
fn new() -> Self { fn new() -> Self {
Self { Self { found_return: false }
found_return: false,
}
} }
} }
@ -244,7 +241,8 @@ impl EarlyLintPass for MiscEarly {
fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat, _: &mut bool) { fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat, _: &mut bool) {
if let PatKind::Struct(ref npat, ref pfields, _) = pat.node { if let PatKind::Struct(ref npat, ref pfields, _) = pat.node {
let mut wilds = 0; let mut wilds = 0;
let type_name = npat.segments let type_name = npat
.segments
.last() .last()
.expect("A path must have at least one segment") .expect("A path must have at least one segment")
.ident .ident
@ -271,8 +269,10 @@ impl EarlyLintPass for MiscEarly {
for field in pfields { for field in pfields {
match field.node.pat.node { match field.node.pat.node {
PatKind::Wild => {}, PatKind::Wild => {},
_ => if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) { _ => {
if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) {
normal.push(n); normal.push(n);
}
}, },
} }
} }
@ -334,7 +334,8 @@ impl EarlyLintPass for MiscEarly {
return; return;
} }
match expr.node { match expr.node {
ExprKind::Call(ref paren, _) => if let ExprKind::Paren(ref closure) = paren.node { ExprKind::Call(ref paren, _) => {
if let ExprKind::Paren(ref closure) = paren.node {
if let ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.node { if let ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.node {
let mut visitor = ReturnVisitor::new(); let mut visitor = ReturnVisitor::new();
visitor.visit_expr(block); visitor.visit_expr(block);
@ -344,7 +345,8 @@ impl EarlyLintPass for MiscEarly {
REDUNDANT_CLOSURE_CALL, REDUNDANT_CLOSURE_CALL,
expr.span, expr.span,
"Try not to call a closure in the expression where it is declared.", "Try not to call a closure in the expression where it is declared.",
|db| if decl.inputs.is_empty() { |db| {
if decl.inputs.is_empty() {
let hint = snippet(cx, block.span, "..").into_owned(); let hint = snippet(cx, block.span, "..").into_owned();
db.span_suggestion_with_applicability( db.span_suggestion_with_applicability(
expr.span, expr.span,
@ -352,18 +354,22 @@ impl EarlyLintPass for MiscEarly {
hint, hint,
Applicability::MachineApplicable, // snippet Applicability::MachineApplicable, // snippet
); );
}
}, },
); );
} }
} }
}
}, },
ExprKind::Unary(UnOp::Neg, ref inner) => if let ExprKind::Unary(UnOp::Neg, _) = inner.node { ExprKind::Unary(UnOp::Neg, ref inner) => {
if let ExprKind::Unary(UnOp::Neg, _) = inner.node {
span_lint( span_lint(
cx, cx,
DOUBLE_NEG, DOUBLE_NEG,
expr.span, expr.span,
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op", "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
); );
}
}, },
ExprKind::Lit(ref lit) => self.check_lit(cx, lit), ExprKind::Lit(ref lit) => self.check_lit(cx, lit),
_ => (), _ => (),

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// This file incorporates work covered by the following copyright and // This file incorporates work covered by the following copyright and
// permission notice: // permission notice:
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
@ -29,13 +28,13 @@
// //
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, LintContext}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty; use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast; use crate::syntax::ast;
use crate::syntax::attr; use crate::syntax::attr;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::{span_lint, in_macro}; use crate::utils::{in_macro, span_lint};
/// **What it does:** Warns if there is missing doc for any documentable item /// **What it does:** Warns if there is missing doc for any documentable item
/// (public or private). /// (public or private).
@ -72,12 +71,16 @@ impl MissingDoc {
} }
fn doc_hidden(&self) -> bool { fn doc_hidden(&self) -> bool {
*self.doc_hidden_stack *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
.last()
.expect("empty doc_hidden_stack")
} }
fn check_missing_docs_attrs(&self, cx: &LateContext<'_, '_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) { fn check_missing_docs_attrs(
&self,
cx: &LateContext<'_, '_>,
attrs: &[ast::Attribute],
sp: Span,
desc: &'static str,
) {
// If we're building a test harness, then warning about // If we're building a test harness, then warning about
// documentation is probably not really relevant right now. // documentation is probably not really relevant right now.
if cx.sess().opts.test { if cx.sess().opts.test {
@ -93,9 +96,7 @@ impl MissingDoc {
return; return;
} }
let has_doc = attrs let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc");
.iter()
.any(|a| a.is_value_str() && a.name() == "doc");
if !has_doc { if !has_doc {
span_lint( span_lint(
cx, cx,
@ -115,8 +116,10 @@ impl LintPass for MissingDoc {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, attrs: &'tcx [ast::Attribute]) { fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, attrs: &'tcx [ast::Attribute]) {
let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { let doc_hidden = self.doc_hidden()
attr.check_name("doc") && match attr.meta_item_list() { || attrs.iter().any(|attr| {
attr.check_name("doc")
&& match attr.meta_item_list() {
None => false, None => false,
Some(l) => attr::list_contains_name(&l[..], "hidden"), Some(l) => attr::list_contains_name(&l[..], "hidden"),
} }
@ -156,10 +159,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
hir::ItemKind::Ty(..) => "a type alias", hir::ItemKind::Ty(..) => "a type alias",
hir::ItemKind::Union(..) => "a union", hir::ItemKind::Union(..) => "a union",
hir::ItemKind::Existential(..) => "an existential type", hir::ItemKind::Existential(..) => "an existential type",
hir::ItemKind::ExternCrate(..) | hir::ItemKind::ExternCrate(..)
hir::ItemKind::ForeignMod(..) | | hir::ItemKind::ForeignMod(..)
hir::ItemKind::Impl(..) | | hir::ItemKind::Impl(..)
hir::ItemKind::Use(..) => return, | hir::ItemKind::Use(..) => return,
}; };
self.check_missing_docs_attrs(cx, &it.attrs, it.span, desc); self.check_missing_docs_attrs(cx, &it.attrs, it.span, desc);
@ -180,8 +183,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
let def_id = cx.tcx.hir.local_def_id(impl_item.id); let def_id = cx.tcx.hir.local_def_id(impl_item.id);
match cx.tcx.associated_item(def_id).container { match cx.tcx.associated_item(def_id).container {
ty::TraitContainer(_) => return, ty::TraitContainer(_) => return,
ty::ImplContainer(cid) => if cx.tcx.impl_trait_ref(cid).is_some() { ty::ImplContainer(cid) => {
if cx.tcx.impl_trait_ref(cid).is_some() {
return; return;
}
}, },
} }

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at // file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT. // http://rust-lang.org/COPYRIGHT.
@ -33,9 +32,9 @@ use crate::utils::span_lint;
/// crates when that's profitable as long as any form of LTO is used. When LTO is disabled, /// crates when that's profitable as long as any form of LTO is used. When LTO is disabled,
/// functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates /// functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates
/// might intend for most of the methods in their public API to be able to be inlined across /// might intend for most of the methods in their public API to be able to be inlined across
/// crates even when LTO is disabled. For these types of crates, enabling this lint might make sense. /// crates even when LTO is disabled. For these types of crates, enabling this lint might make
/// It allows the crate to require all exported methods to be `#[inline]` by default, and then opt /// sense. It allows the crate to require all exported methods to be `#[inline]` by default, and
/// out for specific methods where this might not make sense. /// then opt out for specific methods where this might not make sense.
/// ///
/// **Known problems:** None. /// **Known problems:** None.
/// ///
@ -79,11 +78,8 @@ declare_clippy_lint! {
pub struct MissingInline; pub struct MissingInline;
fn check_missing_inline_attrs(cx: &LateContext<'_, '_>, fn check_missing_inline_attrs(cx: &LateContext<'_, '_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) {
attrs: &[ast::Attribute], sp: Span, desc: &'static str) { let has_inline = attrs.iter().any(|a| a.name() == "inline");
let has_inline = attrs
.iter()
.any(|a| a.name() == "inline" );
if !has_inline { if !has_inline {
span_lint( span_lint(
cx, cx,
@ -97,11 +93,9 @@ fn check_missing_inline_attrs(cx: &LateContext<'_, '_>,
fn is_executable<'a, 'tcx>(cx: &LateContext<'a, 'tcx>) -> bool { fn is_executable<'a, 'tcx>(cx: &LateContext<'a, 'tcx>) -> bool {
use crate::rustc::session::config::CrateType; use crate::rustc::session::config::CrateType;
cx.tcx.sess.crate_types.get().iter().any(|t: &CrateType| { cx.tcx.sess.crate_types.get().iter().any(|t: &CrateType| match t {
match t {
CrateType::Executable => true, CrateType::Executable => true,
_ => false, _ => false,
}
}) })
} }
@ -125,47 +119,44 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline {
let desc = "a function"; let desc = "a function";
check_missing_inline_attrs(cx, &it.attrs, it.span, desc); check_missing_inline_attrs(cx, &it.attrs, it.span, desc);
}, },
hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics, hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics, ref _bounds, ref trait_items) => {
ref _bounds, ref trait_items) => {
// note: we need to check if the trait is exported so we can't use // note: we need to check if the trait is exported so we can't use
// `LateLintPass::check_trait_item` here. // `LateLintPass::check_trait_item` here.
for tit in trait_items { for tit in trait_items {
let tit_ = cx.tcx.hir.trait_item(tit.id); let tit_ = cx.tcx.hir.trait_item(tit.id);
match tit_.node { match tit_.node {
hir::TraitItemKind::Const(..) | hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {},
hir::TraitItemKind::Type(..) => {},
hir::TraitItemKind::Method(..) => { hir::TraitItemKind::Method(..) => {
if tit.defaultness.has_value() { if tit.defaultness.has_value() {
// trait method with default body needs inline in case // trait method with default body needs inline in case
// an impl is not provided // an impl is not provided
let desc = "a default trait method"; let desc = "a default trait method";
let item = cx.tcx.hir.expect_trait_item(tit.id.node_id); let item = cx.tcx.hir.expect_trait_item(tit.id.node_id);
check_missing_inline_attrs(cx, &item.attrs, check_missing_inline_attrs(cx, &item.attrs, item.span, desc);
item.span, desc);
} }
}, },
} }
} }
} },
hir::ItemKind::Const(..) | hir::ItemKind::Const(..)
hir::ItemKind::Enum(..) | | hir::ItemKind::Enum(..)
hir::ItemKind::Mod(..) | | hir::ItemKind::Mod(..)
hir::ItemKind::Static(..) | | hir::ItemKind::Static(..)
hir::ItemKind::Struct(..) | | hir::ItemKind::Struct(..)
hir::ItemKind::TraitAlias(..) | | hir::ItemKind::TraitAlias(..)
hir::ItemKind::GlobalAsm(..) | | hir::ItemKind::GlobalAsm(..)
hir::ItemKind::Ty(..) | | hir::ItemKind::Ty(..)
hir::ItemKind::Union(..) | | hir::ItemKind::Union(..)
hir::ItemKind::Existential(..) | | hir::ItemKind::Existential(..)
hir::ItemKind::ExternCrate(..) | | hir::ItemKind::ExternCrate(..)
hir::ItemKind::ForeignMod(..) | | hir::ItemKind::ForeignMod(..)
hir::ItemKind::Impl(..) | | hir::ItemKind::Impl(..)
hir::ItemKind::Use(..) => {}, | hir::ItemKind::Use(..) => {},
}; };
} }
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx hir::ImplItem) { fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx hir::ImplItem) {
use crate::rustc::ty::{TraitContainer, ImplContainer}; use crate::rustc::ty::{ImplContainer, TraitContainer};
if is_executable(cx) { if is_executable(cx) {
return; return;
} }
@ -177,9 +168,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline {
let desc = match impl_item.node { let desc = match impl_item.node {
hir::ImplItemKind::Method(..) => "a method", hir::ImplItemKind::Method(..) => "a method",
hir::ImplItemKind::Const(..) | hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) | hir::ImplItemKind::Existential(_) => return,
hir::ImplItemKind::Type(_) |
hir::ImplItemKind::Existential(_) => return,
}; };
let def_id = cx.tcx.hir.local_def_id(impl_item.id); let def_id = cx.tcx.hir.local_def_id(impl_item.id);

View file

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::hir::intravisit; use crate::rustc::hir::intravisit;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty; use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::{higher, span_lint}; use crate::utils::{higher, span_lint};
/// **What it does:** Checks for instances of `mut mut` references. /// **What it does:** Checks for instances of `mut mut` references.
@ -81,12 +80,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
expr.span, expr.span,
"generally you want to avoid `&mut &mut _` if possible", "generally you want to avoid `&mut &mut _` if possible",
); );
} else if let ty::Ref( } else if let ty::Ref(_, _, hir::MutMutable) = self.cx.tables.expr_ty(e).sty {
_,
_,
hir::MutMutable,
) = self.cx.tables.expr_ty(e).sty
{
span_lint( span_lint(
self.cx, self.cx,
MUT_MUT, MUT_MUT,
@ -109,8 +103,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
if let hir::TyKind::Rptr( if let hir::TyKind::Rptr(
_, _,
hir::MutTy { hir::MutTy {
mutbl: hir::MutMutable, mutbl: hir::MutMutable, ..
..
}, },
) = pty.node ) = pty.node
{ {

View file

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty::{self, Ty};
use crate::rustc::ty::subst::Subst;
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::subst::Subst;
use crate::rustc::ty::{self, Ty};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::span_lint; use crate::utils::span_lint;
/// **What it does:** Detects giving a mutable reference to a function that only /// **What it does:** Detects giving a mutable reference to a function that only
@ -30,11 +29,9 @@ use crate::utils::span_lint;
declare_clippy_lint! { declare_clippy_lint! {
pub UNNECESSARY_MUT_PASSED, pub UNNECESSARY_MUT_PASSED,
style, style,
"an argument passed as a mutable reference although the callee only demands an \ "an argument passed as a mutable reference although the callee only demands an immutable reference"
immutable reference"
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct UnnecessaryMutPassed; pub struct UnnecessaryMutPassed;
@ -47,13 +44,15 @@ impl LintPass for UnnecessaryMutPassed {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
match e.node { match e.node {
ExprKind::Call(ref fn_expr, ref arguments) => if let ExprKind::Path(ref path) = fn_expr.node { ExprKind::Call(ref fn_expr, ref arguments) => {
if let ExprKind::Path(ref path) = fn_expr.node {
check_arguments( check_arguments(
cx, cx,
arguments, arguments,
cx.tables.expr_ty(fn_expr), cx.tables.expr_ty(fn_expr),
&print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)), &print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)),
); );
}
}, },
ExprKind::MethodCall(ref path, _, ref arguments) => { ExprKind::MethodCall(ref path, _, ref arguments) => {
let def_id = cx.tables.type_dependent_defs()[e.hir_id].def_id(); let def_id = cx.tables.type_dependent_defs()[e.hir_id].def_id();
@ -72,21 +71,18 @@ fn check_arguments<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arguments: &[Expr], typ
let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs(); let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
for (argument, parameter) in arguments.iter().zip(parameters.iter()) { for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
match parameter.sty { match parameter.sty {
ty::Ref( ty::Ref(_, _, MutImmutable)
_, | ty::RawPtr(ty::TypeAndMut {
_, mutbl: MutImmutable, ..
MutImmutable, }) => {
) | if let ExprKind::AddrOf(MutMutable, _) = argument.node {
ty::RawPtr(ty::TypeAndMut {
mutbl: MutImmutable,
..
}) => if let ExprKind::AddrOf(MutMutable, _) = argument.node {
span_lint( span_lint(
cx, cx,
UNNECESSARY_MUT_PASSED, UNNECESSARY_MUT_PASSED,
argument.span, argument.span,
&format!("The function/method `{}` doesn't need a mutable reference", name), &format!("The function/method `{}` doesn't need a mutable reference", name),
); );
}
}, },
_ => (), _ => (),
} }

View file

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! Checks for uses of mutex where an atomic value could be used //! Checks for uses of mutex where an atomic value could be used
//! //!
//! This lint is **warn** by default //! This lint is **warn** by default
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty::{self, Ty};
use crate::rustc::hir::Expr; use crate::rustc::hir::Expr;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty::{self, Ty};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::ast; use crate::syntax::ast;
use crate::utils::{match_type, paths, span_lint}; use crate::utils::{match_type, paths, span_lint};

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! Checks for needless boolean results of if-else expressions //! Checks for needless boolean results of if-else expressions
//! //!
//! This lint is **warn** by default //! This lint is **warn** by default
@ -34,13 +33,16 @@ use crate::utils::{in_macro, snippet_with_applicability, span_lint, span_lint_an
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// if x { false } else { true } /// if x {
/// false
/// } else {
/// true
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub NEEDLESS_BOOL, pub NEEDLESS_BOOL,
complexity, complexity,
"if-statements with plain booleans in the then- and else-clause, e.g. \ "if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }`"
`if p { true } else { false }`"
} }
/// **What it does:** Checks for expressions of the form `x == true` (or vice /// **What it does:** Checks for expressions of the form `x == true` (or vice
@ -52,7 +54,7 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// if x == true { } // could be `if x { }` /// if x == true {} // could be `if x { }`
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub BOOL_COMPARISON, pub BOOL_COMPARISON,
@ -142,7 +144,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
return; return;
} }
if let ExprKind::Binary(Spanned { node: BinOpKind::Eq, .. }, ref left_side, ref right_side) = e.node { if let ExprKind::Binary(
Spanned {
node: BinOpKind::Eq, ..
},
ref left_side,
ref right_side,
) = e.node
{
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) { match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
(Bool(true), Other) => { (Bool(true), Other) => {
@ -208,7 +217,8 @@ enum Expression {
fn fetch_bool_block(block: &Block) -> Expression { fn fetch_bool_block(block: &Block) -> Expression {
match (&*block.stmts, block.expr.as_ref()) { match (&*block.stmts, block.expr.as_ref()) {
(&[], Some(e)) => fetch_bool_expr(&**e), (&[], Some(e)) => fetch_bool_expr(&**e),
(&[ref e], None) => if let StmtKind::Semi(ref e, _) = e.node { (&[ref e], None) => {
if let StmtKind::Semi(ref e, _) = e.node {
if let ExprKind::Ret(_) = e.node { if let ExprKind::Ret(_) = e.node {
fetch_bool_expr(&**e) fetch_bool_expr(&**e)
} else { } else {
@ -216,6 +226,7 @@ fn fetch_bool_block(block: &Block) -> Expression {
} }
} else { } else {
Expression::Other Expression::Other
}
}, },
_ => Expression::Other, _ => Expression::Other,
} }
@ -224,10 +235,12 @@ fn fetch_bool_block(block: &Block) -> Expression {
fn fetch_bool_expr(expr: &Expr) -> Expression { fn fetch_bool_expr(expr: &Expr) -> Expression {
match expr.node { match expr.node {
ExprKind::Block(ref block, _) => fetch_bool_block(block), ExprKind::Block(ref block, _) => fetch_bool_block(block),
ExprKind::Lit(ref lit_ptr) => if let LitKind::Bool(value) = lit_ptr.node { ExprKind::Lit(ref lit_ptr) => {
if let LitKind::Bool(value) = lit_ptr.node {
Expression::Bool(value) Expression::Bool(value)
} else { } else {
Expression::Other Expression::Other
}
}, },
ExprKind::Ret(Some(ref expr)) => match fetch_bool_expr(expr) { ExprKind::Ret(Some(ref expr)) => match fetch_bool_expr(expr) {
Expression::Bool(value) => Expression::RetBool(value), Expression::Bool(value) => Expression::RetBool(value),

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! Checks for needless address of operations (`&`) //! Checks for needless address of operations (`&`)
//! //!
//! This lint is **warn** by default //! This lint is **warn** by default
@ -18,8 +17,8 @@ use crate::rustc::ty;
use crate::rustc::ty::adjustment::{Adjust, Adjustment}; use crate::rustc::ty::adjustment::{Adjust, Adjustment};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::utils::{in_macro, snippet_opt, span_lint_and_then};
use crate::syntax::ast::NodeId; use crate::syntax::ast::NodeId;
use crate::utils::{in_macro, snippet_opt, span_lint_and_then};
use if_chain::if_chain; use if_chain::if_chain;
/// **What it does:** Checks for address of operations (`&`) that are going to /// **What it does:** Checks for address of operations (`&`) that are going to
@ -60,11 +59,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrow {
if let ty::Ref(..) = cx.tables.expr_ty(inner).sty { if let ty::Ref(..) = cx.tables.expr_ty(inner).sty {
for adj3 in cx.tables.expr_adjustments(e).windows(3) { for adj3 in cx.tables.expr_adjustments(e).windows(3) {
if let [Adjustment { if let [Adjustment {
kind: Adjust::Deref(_), kind: Adjust::Deref(_), ..
..
}, Adjustment { }, Adjustment {
kind: Adjust::Deref(_), kind: Adjust::Deref(_), ..
..
}, Adjustment { }, Adjustment {
kind: Adjust::Borrow(_), kind: Adjust::Borrow(_),
.. ..

View file

@ -7,17 +7,16 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! Checks for useless borrowed references. //! Checks for useless borrowed references.
//! //!
//! This lint is **warn** by default //! This lint is **warn** by default
use crate::rustc::hir::{BindingAnnotation, MutImmutable, Pat, PatKind};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::hir::{BindingAnnotation, MutImmutable, Pat, PatKind};
use crate::utils::{in_macro, snippet, span_lint_and_then};
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::utils::{in_macro, snippet, span_lint_and_then};
use if_chain::if_chain;
/// **What it does:** Checks for useless borrowed references. /// **What it does:** Checks for useless borrowed references.
/// ///

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! Checks for continue statements in loops that are redundant. //! Checks for continue statements in loops that are redundant.
//! //!
//! For example, the lint would catch //! For example, the lint would catch
@ -181,7 +180,6 @@ impl EarlyLintPass for NeedlessContinue {
/// - The expression is a `continue` node. /// - The expression is a `continue` node.
/// - The expression node is a block with the first statement being a /// - The expression node is a block with the first statement being a
/// `continue`. /// `continue`.
///
fn needless_continue_in_else(else_expr: &ast::Expr) -> bool { fn needless_continue_in_else(else_expr: &ast::Expr) -> bool {
match else_expr.node { match else_expr.node {
ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block), ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block),
@ -192,10 +190,12 @@ fn needless_continue_in_else(else_expr: &ast::Expr) -> bool {
fn is_first_block_stmt_continue(block: &ast::Block) -> bool { fn is_first_block_stmt_continue(block: &ast::Block) -> bool {
block.stmts.get(0).map_or(false, |stmt| match stmt.node { block.stmts.get(0).map_or(false, |stmt| match stmt.node {
ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => if let ast::ExprKind::Continue(_) = e.node { ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
if let ast::ExprKind::Continue(_) = e.node {
true true
} else { } else {
false false
}
}, },
_ => false, _ => false,
}) })
@ -208,10 +208,10 @@ where
F: FnMut(&ast::Block), F: FnMut(&ast::Block),
{ {
match expr.node { match expr.node {
ast::ExprKind::While(_, ref loop_block, _) | ast::ExprKind::While(_, ref loop_block, _)
ast::ExprKind::WhileLet(_, _, ref loop_block, _) | | ast::ExprKind::WhileLet(_, _, ref loop_block, _)
ast::ExprKind::ForLoop(_, _, ref loop_block, _) | | ast::ExprKind::ForLoop(_, _, ref loop_block, _)
ast::ExprKind::Loop(ref loop_block, _) => func(loop_block), | ast::ExprKind::Loop(ref loop_block, _) => func(loop_block),
_ => {}, _ => {},
} }
} }
@ -224,7 +224,6 @@ where
/// - The `if` condition expression, /// - The `if` condition expression,
/// - The `then` block, and /// - The `then` block, and
/// - The `else` expression. /// - The `else` expression.
///
fn with_if_expr<F>(stmt: &ast::Stmt, mut func: F) fn with_if_expr<F>(stmt: &ast::Stmt, mut func: F)
where where
F: FnMut(&ast::Expr, &ast::Expr, &ast::Block, &ast::Expr), F: FnMut(&ast::Expr, &ast::Expr, &ast::Block, &ast::Expr),
@ -274,7 +273,6 @@ const DROP_ELSE_BLOCK_AND_MERGE_MSG: &str = "Consider dropping the else clause a
const DROP_ELSE_BLOCK_MSG: &str = "Consider dropping the else clause, and moving out the code in the else \ const DROP_ELSE_BLOCK_MSG: &str = "Consider dropping the else clause, and moving out the code in the else \
block, like so:\n"; block, like so:\n";
fn emit_warning<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, typ: LintType) { fn emit_warning<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, typ: LintType) {
// snip is the whole *help* message that appears after the warning. // snip is the whole *help* message that appears after the warning.
// message is the warning message. // message is the warning message.
@ -294,7 +292,11 @@ fn emit_warning<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str
span_help_and_lint(ctx, NEEDLESS_CONTINUE, expr.span, message, &snip); span_help_and_lint(ctx, NEEDLESS_CONTINUE, expr.span, message, &snip);
} }
fn suggestion_snippet_for_continue_inside_if<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str) -> String { fn suggestion_snippet_for_continue_inside_if<'a>(
ctx: &EarlyContext<'_>,
data: &'a LintData<'_>,
header: &str,
) -> String {
let cond_code = snippet(ctx, data.if_cond.span, ".."); let cond_code = snippet(ctx, data.if_cond.span, "..");
let if_code = format!("if {} {{\n continue;\n}}\n", cond_code); let if_code = format!("if {} {{\n continue;\n}}\n", cond_code);
@ -311,7 +313,11 @@ fn suggestion_snippet_for_continue_inside_if<'a>(ctx: &EarlyContext<'_>, data: &
ret ret
} }
fn suggestion_snippet_for_continue_inside_else<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str) -> String { fn suggestion_snippet_for_continue_inside_else<'a>(
ctx: &EarlyContext<'_>,
data: &'a LintData<'_>,
header: &str,
) -> String {
let cond_code = snippet(ctx, data.if_cond.span, ".."); let cond_code = snippet(ctx, data.if_cond.span, "..");
let mut if_code = format!("if {} {{\n", cond_code); let mut if_code = format!("if {} {{\n", cond_code);
@ -355,7 +361,12 @@ fn check_and_warn<'a>(ctx: &EarlyContext<'_>, expr: &'a ast::Expr) {
block_stmts: &loop_block.stmts, block_stmts: &loop_block.stmts,
}; };
if needless_continue_in_else(else_expr) { if needless_continue_in_else(else_expr) {
emit_warning(ctx, data, DROP_ELSE_BLOCK_AND_MERGE_MSG, LintType::ContinueInsideElseBlock); emit_warning(
ctx,
data,
DROP_ELSE_BLOCK_AND_MERGE_MSG,
LintType::ContinueInsideElseBlock,
);
} else if is_first_block_stmt_continue(then_block) { } else if is_first_block_stmt_continue(then_block) {
emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock); emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
} }
@ -413,7 +424,6 @@ pub fn erode_from_back(s: &str) -> String {
/// inside_a_block(); /// inside_a_block();
/// } /// }
/// ``` /// ```
///
pub fn erode_from_front(s: &str) -> String { pub fn erode_from_front(s: &str) -> String {
s.chars() s.chars()
.skip_while(|c| c.is_whitespace()) .skip_while(|c| c.is_whitespace())

View file

@ -7,27 +7,28 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use matches::matches;
use crate::rustc::hir::*;
use crate::rustc::hir::intravisit::FnKind; use crate::rustc::hir::intravisit::FnKind;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty::{self, RegionKind, TypeFoldable};
use crate::rustc::traits;
use crate::rustc::middle::expr_use_visitor as euv; use crate::rustc::middle::expr_use_visitor as euv;
use crate::rustc::middle::mem_categorization as mc; use crate::rustc::middle::mem_categorization as mc;
use crate::rustc_target::spec::abi::Abi; use crate::rustc::traits;
use crate::rustc::ty::{self, RegionKind, TypeFoldable};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet}; use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet};
use crate::syntax::ast::NodeId;
use crate::syntax_pos::Span;
use crate::syntax::errors::DiagnosticBuilder;
use crate::utils::{get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths,
snippet, snippet_opt, span_lint_and_then};
use crate::utils::ptr::get_spans;
use std::borrow::Cow;
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::rustc_target::spec::abi::Abi;
use crate::syntax::ast::NodeId;
use crate::syntax::errors::DiagnosticBuilder;
use crate::syntax_pos::Span;
use crate::utils::ptr::get_spans;
use crate::utils::{
get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths, snippet,
snippet_opt, span_lint_and_then,
};
use if_chain::if_chain;
use matches::matches;
use std::borrow::Cow;
/// **What it does:** Checks for functions taking arguments by value, but not /// **What it does:** Checks for functions taking arguments by value, but not
/// consuming them in its /// consuming them in its
@ -67,7 +68,13 @@ impl LintPass for NeedlessPassByValue {
} }
macro_rules! need { macro_rules! need {
($e: expr) => { if let Some(x) = $e { x } else { return; } }; ($e: expr) => {
if let Some(x) = $e {
x
} else {
return;
}
};
} }
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
@ -114,7 +121,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
need!(cx.tcx.lang_items().fn_trait()), need!(cx.tcx.lang_items().fn_trait()),
need!(cx.tcx.lang_items().fn_once_trait()), need!(cx.tcx.lang_items().fn_once_trait()),
need!(cx.tcx.lang_items().fn_mut_trait()), need!(cx.tcx.lang_items().fn_mut_trait()),
need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT)) need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT)),
]; ];
let sized_trait = need!(cx.tcx.lang_items().sized_trait()); let sized_trait = need!(cx.tcx.lang_items().sized_trait());
@ -125,7 +132,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
.filter(|p| !p.is_global()) .filter(|p| !p.is_global())
.filter_map(|pred| { .filter_map(|pred| {
if let ty::Predicate::Trait(poly_trait_ref) = pred { if let ty::Predicate::Trait(poly_trait_ref) = pred {
if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_bound_vars() { if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_bound_vars()
{
return None; return None;
} }
Some(poly_trait_ref) Some(poly_trait_ref)
@ -152,12 +160,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
let fn_sig = cx.tcx.fn_sig(fn_def_id); let fn_sig = cx.tcx.fn_sig(fn_def_id);
let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig); let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig);
for (idx, ((input, &ty), arg)) in decl.inputs for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(&body.arguments).enumerate() {
.iter()
.zip(fn_sig.inputs())
.zip(&body.arguments)
.enumerate()
{
// All spans generated from a proc-macro invocation are the same... // All spans generated from a proc-macro invocation are the same...
if span == input.span { if span == input.span {
return; return;
@ -172,9 +175,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
} }
} }
//
// * Exclude a type that is specifically bounded by `Borrow`. // * Exclude a type that is specifically bounded by `Borrow`.
// * Exclude a type whose reference also fulfills its bound. // * Exclude a type whose reference also fulfills its bound. (e.g. `std::convert::AsRef`,
// (e.g. `std::convert::AsRef`, `serde::Serialize`) // `serde::Serialize`)
let (implements_borrow_trait, all_borrowable_trait) = { let (implements_borrow_trait, all_borrowable_trait) = {
let preds = preds let preds = preds
.iter() .iter()
@ -183,16 +187,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
( (
preds.iter().any(|t| t.def_id() == borrow_trait), preds.iter().any(|t| t.def_id() == borrow_trait),
!preds.is_empty() && preds.iter().all(|t| { !preds.is_empty()
let ty_params = &t.skip_binder().trait_ref.substs.iter().skip(1) && preds.iter().all(|t| {
let ty_params = &t
.skip_binder()
.trait_ref
.substs
.iter()
.skip(1)
.cloned() .cloned()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
implements_trait( implements_trait(cx, cx.tcx.mk_imm_ref(&RegionKind::ReErased, ty), t.def_id(), ty_params)
cx,
cx.tcx.mk_imm_ref(&RegionKind::ReErased, ty),
t.def_id(),
ty_params
)
}), }),
) )
}; };
@ -415,14 +420,22 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> {
} }
} }
fn borrow(&mut self, _: NodeId, _: Span, _: &mc::cmt_<'tcx>, _: ty::Region<'_>, _: ty::BorrowKind, _: euv::LoanCause) {} fn borrow(
&mut self,
_: NodeId,
_: Span,
_: &mc::cmt_<'tcx>,
_: ty::Region<'_>,
_: ty::BorrowKind,
_: euv::LoanCause,
) {
}
fn mutate(&mut self, _: NodeId, _: Span, _: &mc::cmt_<'tcx>, _: euv::MutateMode) {} fn mutate(&mut self, _: NodeId, _: Span, _: &mc::cmt_<'tcx>, _: euv::MutateMode) {}
fn decl_without_init(&mut self, _: NodeId, _: Span) {} fn decl_without_init(&mut self, _: NodeId, _: Span) {}
} }
fn unwrap_downcast_or_interior<'a, 'tcx>(mut cmt: &'a mc::cmt_<'tcx>) -> mc::cmt_<'tcx> { fn unwrap_downcast_or_interior<'a, 'tcx>(mut cmt: &'a mc::cmt_<'tcx>) -> mc::cmt_<'tcx> {
loop { loop {
match cmt.cat { match cmt.cat {
@ -431,5 +444,5 @@ fn unwrap_downcast_or_interior<'a, 'tcx>(mut cmt: &'a mc::cmt_<'tcx>) -> mc::cmt
}, },
_ => return (*cmt).clone(), _ => return (*cmt).clone(),
} }
}; }
} }

View file

@ -7,11 +7,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::ty;
use crate::rustc::hir::{Expr, ExprKind}; use crate::rustc::hir::{Expr, ExprKind};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::utils::span_lint; use crate::utils::span_lint;
/// **What it does:** Checks for needlessly including a base struct on update /// **What it does:** Checks for needlessly including a base struct on update
@ -24,7 +23,11 @@ use crate::utils::span_lint;
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// Point { x: 1, y: 0, ..zero_point } /// Point {
/// x: 1,
/// y: 0,
/// ..zero_point
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub NEEDLESS_UPDATE, pub NEEDLESS_UPDATE,

View file

@ -7,9 +7,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain; use if_chain::if_chain;
@ -61,7 +60,6 @@ impl LintPass for NoNegCompOpForPartialOrd {
} }
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NoNegCompOpForPartialOrd { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NoNegCompOpForPartialOrd {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_chain! { if_chain! {

View file

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::syntax::source_map::{Span, Spanned}; use crate::syntax::source_map::{Span, Spanned};
use if_chain::if_chain;
use crate::consts::{self, Constant}; use crate::consts::{self, Constant};
use crate::utils::span_lint; use crate::utils::span_lint;
@ -45,7 +44,14 @@ impl LintPass for NegMultiply {
#[allow(clippy::match_same_arms)] #[allow(clippy::match_same_arms)]
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NegMultiply { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NegMultiply {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
if let ExprKind::Binary(Spanned { node: BinOpKind::Mul, .. }, ref l, ref r) = e.node { if let ExprKind::Binary(
Spanned {
node: BinOpKind::Mul, ..
},
ref l,
ref r,
) = e.node
{
match (&l.node, &r.node) { match (&l.node, &r.node) {
(&ExprKind::Unary(..), &ExprKind::Unary(..)) => (), (&ExprKind::Unary(..), &ExprKind::Unary(..)) => (),
(&ExprKind::Unary(UnNeg, ref lit), _) => check_mul(cx, e.span, lit, r), (&ExprKind::Unary(UnNeg, ref lit), _) => check_mul(cx, e.span, lit, r),

View file

@ -7,19 +7,18 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::def_id::DefId;
use crate::rustc::hir; use crate::rustc::hir;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext}; use crate::rustc::hir::def_id::DefId;
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use crate::rustc::ty::{self, Ty};
use crate::rustc::util::nodemap::NodeSet; use crate::rustc::util::nodemap::NodeSet;
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain; use crate::rustc_errors::Applicability;
use crate::rustc::ty::{self, Ty};
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::utils::paths; use crate::utils::paths;
use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_and_then};
use crate::utils::sugg::DiagnosticBuilderExt; use crate::utils::sugg::DiagnosticBuilderExt;
use crate::rustc_errors::Applicability; use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_and_then};
use if_chain::if_chain;
/// **What it does:** Checks for types with a `fn new() -> Self` method and no /// **What it does:** Checks for types with a `fn new() -> Self` method and no
/// implementation of /// implementation of
@ -125,7 +124,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
} }
if impl_item.generics.params.iter().any(|gen| match gen.kind { if impl_item.generics.params.iter().any(|gen| match gen.kind {
hir::GenericParamKind::Type { .. } => true, hir::GenericParamKind::Type { .. } => true,
_ => false _ => false,
}) { }) {
// when the result of `new()` depends on a type parameter we should not require // when the result of `new()` depends on a type parameter we should not require
// an // an
@ -134,8 +133,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
} }
if sig.decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) { if sig.decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) {
let self_did = cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id)); let self_did = cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id));
let self_ty = cx.tcx let self_ty = cx.tcx.type_of(self_did);
.type_of(self_did);
if_chain! { if_chain! {
if same_tys(cx, self_ty, return_ty(cx, id)); if same_tys(cx, self_ty, return_ty(cx, id));
if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT); if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
@ -171,7 +169,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
cx, cx,
NEW_WITHOUT_DEFAULT_DERIVE, NEW_WITHOUT_DEFAULT_DERIVE,
impl_item.span, impl_item.span,
&format!("you should consider deriving a `Default` implementation for `{}`", self_ty), &format!(
"you should consider deriving a `Default` implementation for `{}`",
self_ty
),
|db| { |db| {
db.suggest_item_with_attr( db.suggest_item_with_attr(
cx, cx,
@ -186,7 +187,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
cx, cx,
NEW_WITHOUT_DEFAULT, NEW_WITHOUT_DEFAULT,
impl_item.span, impl_item.span,
&format!("you should consider adding a `Default` implementation for `{}`", self_ty), &format!(
"you should consider adding a `Default` implementation for `{}`",
self_ty
),
|db| { |db| {
db.suggest_prepend_item( db.suggest_prepend_item(
cx, cx,

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::def::Def; use crate::rustc::hir::def::Def;
use crate::rustc::hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource}; use crate::rustc::hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
@ -63,20 +62,23 @@ fn has_no_effect(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
has_no_effect(cx, a) && has_no_effect(cx, b) has_no_effect(cx, a) && has_no_effect(cx, b)
}, },
ExprKind::Array(ref v) | ExprKind::Tup(ref v) => v.iter().all(|val| has_no_effect(cx, val)), ExprKind::Array(ref v) | ExprKind::Tup(ref v) => v.iter().all(|val| has_no_effect(cx, val)),
ExprKind::Repeat(ref inner, _) | ExprKind::Repeat(ref inner, _)
ExprKind::Cast(ref inner, _) | | ExprKind::Cast(ref inner, _)
ExprKind::Type(ref inner, _) | | ExprKind::Type(ref inner, _)
ExprKind::Unary(_, ref inner) | | ExprKind::Unary(_, ref inner)
ExprKind::Field(ref inner, _) | | ExprKind::Field(ref inner, _)
ExprKind::AddrOf(_, ref inner) | | ExprKind::AddrOf(_, ref inner)
ExprKind::Box(ref inner) => has_no_effect(cx, inner), | ExprKind::Box(ref inner) => has_no_effect(cx, inner),
ExprKind::Struct(_, ref fields, ref base) => { ExprKind::Struct(_, ref fields, ref base) => {
!has_drop(cx, expr) && fields.iter().all(|field| has_no_effect(cx, &field.expr)) && match *base { !has_drop(cx, expr)
&& fields.iter().all(|field| has_no_effect(cx, &field.expr))
&& match *base {
Some(ref base) => has_no_effect(cx, base), Some(ref base) => has_no_effect(cx, base),
None => true, None => true,
} }
}, },
ExprKind::Call(ref callee, ref args) => if let ExprKind::Path(ref qpath) = callee.node { ExprKind::Call(ref callee, ref args) => {
if let ExprKind::Path(ref qpath) = callee.node {
let def = cx.tables.qpath_def(qpath, callee.hir_id); let def = cx.tables.qpath_def(qpath, callee.hir_id);
match def { match def {
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) => { Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) => {
@ -86,9 +88,11 @@ fn has_no_effect(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
} }
} else { } else {
false false
}
}, },
ExprKind::Block(ref block, _) => { ExprKind::Block(ref block, _) => {
block.stmts.is_empty() && if let Some(ref expr) = block.expr { block.stmts.is_empty()
&& if let Some(ref expr) = block.expr {
has_no_effect(cx, expr) has_no_effect(cx, expr)
} else { } else {
false false
@ -139,7 +143,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
} }
} }
fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<Vec<&'a Expr>> { fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<Vec<&'a Expr>> {
if in_macro(expr.span) { if in_macro(expr.span) {
return None; return None;
@ -150,26 +153,22 @@ fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<Vec
Some(vec![&**a, &**b]) Some(vec![&**a, &**b])
}, },
ExprKind::Array(ref v) | ExprKind::Tup(ref v) => Some(v.iter().collect()), ExprKind::Array(ref v) | ExprKind::Tup(ref v) => Some(v.iter().collect()),
ExprKind::Repeat(ref inner, _) | ExprKind::Repeat(ref inner, _)
ExprKind::Cast(ref inner, _) | | ExprKind::Cast(ref inner, _)
ExprKind::Type(ref inner, _) | | ExprKind::Type(ref inner, _)
ExprKind::Unary(_, ref inner) | | ExprKind::Unary(_, ref inner)
ExprKind::Field(ref inner, _) | | ExprKind::Field(ref inner, _)
ExprKind::AddrOf(_, ref inner) | | ExprKind::AddrOf(_, ref inner)
ExprKind::Box(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])), | ExprKind::Box(ref inner) => reduce_expression(cx, inner).or_else(|| Some(vec![inner])),
ExprKind::Struct(_, ref fields, ref base) => if has_drop(cx, expr) { ExprKind::Struct(_, ref fields, ref base) => {
if has_drop(cx, expr) {
None None
} else { } else {
Some( Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect())
fields }
.iter()
.map(|f| &f.expr)
.chain(base)
.map(Deref::deref)
.collect(),
)
}, },
ExprKind::Call(ref callee, ref args) => if let ExprKind::Path(ref qpath) = callee.node { ExprKind::Call(ref callee, ref args) => {
if let ExprKind::Path(ref qpath) = callee.node {
let def = cx.tables.qpath_def(qpath, callee.hir_id); let def = cx.tables.qpath_def(qpath, callee.hir_id);
match def { match def {
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..)
@ -181,6 +180,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<Vec
} }
} else { } else {
None None
}
}, },
ExprKind::Block(ref block, _) => { ExprKind::Block(ref block, _) => {
if block.stmts.is_empty() { if block.stmts.is_empty() {

View file

@ -7,22 +7,21 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! Checks for uses of const which the type is not Freeze (Cell-free). //! Checks for uses of const which the type is not Freeze (Cell-free).
//! //!
//! This lint is **deny** by default. //! This lint is **deny** by default.
use crate::rustc::lint::{LateContext, LateLintPass, Lint, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc::hir::*;
use crate::rustc::hir::def::Def; use crate::rustc::hir::def::Def;
use crate::rustc::ty::{self, TypeFlags}; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, Lint, LintArray, LintPass};
use crate::rustc::ty::adjustment::Adjust; use crate::rustc::ty::adjustment::Adjust;
use crate::rustc::ty::{self, TypeFlags};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::rustc_typeck::hir_ty_to_ty; use crate::rustc_typeck::hir_ty_to_ty;
use crate::syntax_pos::{DUMMY_SP, Span}; use crate::syntax_pos::{Span, DUMMY_SP};
use std::ptr;
use crate::utils::{in_constant, in_macro, is_copy, span_lint_and_then}; use crate::utils::{in_constant, in_macro, is_copy, span_lint_and_then};
use std::ptr;
/// **What it does:** Checks for declaration of `const` items which is interior /// **What it does:** Checks for declaration of `const` items which is interior
/// mutable (e.g. contains a `Cell`, `Mutex`, `AtomicXxxx` etc). /// mutable (e.g. contains a `Cell`, `Mutex`, `AtomicXxxx` etc).
@ -42,7 +41,7 @@ use crate::utils::{in_constant, in_macro, is_copy, span_lint_and_then};
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// use std::sync::atomic::{Ordering::SeqCst, AtomicUsize}; /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
/// ///
/// // Bad. /// // Bad.
/// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
@ -74,7 +73,7 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// use std::sync::atomic::{Ordering::SeqCst, AtomicUsize}; /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
/// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); /// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
/// ///
/// // Bad. /// // Bad.
@ -94,16 +93,9 @@ declare_clippy_lint! {
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
enum Source { enum Source {
Item { Item { item: Span },
item: Span, Assoc { item: Span, ty: Span },
}, Expr { expr: Span },
Assoc {
item: Span,
ty: Span,
},
Expr {
expr: Span,
},
} }
impl Source { impl Source {
@ -123,11 +115,7 @@ impl Source {
} }
} }
fn verify_ty_bound<'a, 'tcx>( fn verify_ty_bound<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: ty::Ty<'tcx>, source: Source) {
cx: &LateContext<'a, 'tcx>,
ty: ty::Ty<'tcx>,
source: Source,
) {
if ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP) || is_copy(cx, ty) { if ty.is_freeze(cx.tcx, cx.param_env, DUMMY_SP) || is_copy(cx, ty) {
// an UnsafeCell is !Copy, and an UnsafeCell is also the only type which // an UnsafeCell is !Copy, and an UnsafeCell is also the only type which
// is !Freeze, thus if our type is Copy we can be sure it must be Freeze // is !Freeze, thus if our type is Copy we can be sure it must be Freeze
@ -149,22 +137,19 @@ fn verify_ty_bound<'a, 'tcx>(
"static".to_string(), "static".to_string(),
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} },
Source::Assoc { ty: ty_span, .. } => { Source::Assoc { ty: ty_span, .. } => {
if ty.flags.contains(TypeFlags::HAS_FREE_LOCAL_NAMES) { if ty.flags.contains(TypeFlags::HAS_FREE_LOCAL_NAMES) {
db.span_help(ty_span, &format!("consider requiring `{}` to be `Copy`", ty)); db.span_help(ty_span, &format!("consider requiring `{}` to be `Copy`", ty));
} }
} },
Source::Expr { .. } => { Source::Expr { .. } => {
db.help( db.help("assign this const to a local or static variable, and use the variable here");
"assign this const to a local or static variable, and use the variable here", },
);
}
} }
}); });
} }
pub struct NonCopyConst; pub struct NonCopyConst;
impl LintPass for NonCopyConst { impl LintPass for NonCopyConst {
@ -184,7 +169,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst {
fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, trait_item: &'tcx TraitItem) { fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, trait_item: &'tcx TraitItem) {
if let TraitItemKind::Const(hir_ty, ..) = &trait_item.node { if let TraitItemKind::Const(hir_ty, ..) = &trait_item.node {
let ty = hir_ty_to_ty(cx.tcx, hir_ty); let ty = hir_ty_to_ty(cx.tcx, hir_ty);
verify_ty_bound(cx, ty, Source::Assoc { ty: hir_ty.span, item: trait_item.span }); verify_ty_bound(
cx,
ty,
Source::Assoc {
ty: hir_ty.span,
item: trait_item.span,
},
);
} }
} }
@ -195,7 +187,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst {
// ensure the impl is an inherent impl. // ensure the impl is an inherent impl.
if let ItemKind::Impl(_, _, _, _, None, _, _) = item.node { if let ItemKind::Impl(_, _, _, _, None, _, _) = item.node {
let ty = hir_ty_to_ty(cx.tcx, hir_ty); let ty = hir_ty_to_ty(cx.tcx, hir_ty);
verify_ty_bound(cx, ty, Source::Assoc { ty: hir_ty.span, item: impl_item.span }); verify_ty_bound(
cx,
ty,
Source::Assoc {
ty: hir_ty.span,
item: impl_item.span,
},
);
} }
} }
} }
@ -227,25 +226,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonCopyConst {
ExprKind::AddrOf(..) => { ExprKind::AddrOf(..) => {
// `&e` => `e` must be referenced // `&e` => `e` must be referenced
needs_check_adjustment = false; needs_check_adjustment = false;
} },
ExprKind::Field(..) => { ExprKind::Field(..) => {
dereferenced_expr = parent_expr; dereferenced_expr = parent_expr;
needs_check_adjustment = true; needs_check_adjustment = true;
} },
ExprKind::Index(e, _) if ptr::eq(&**e, cur_expr) => { ExprKind::Index(e, _) if ptr::eq(&**e, cur_expr) => {
// `e[i]` => desugared to `*Index::index(&e, i)`, // `e[i]` => desugared to `*Index::index(&e, i)`,
// meaning `e` must be referenced. // meaning `e` must be referenced.
// no need to go further up since a method call is involved now. // no need to go further up since a method call is involved now.
needs_check_adjustment = false; needs_check_adjustment = false;
break; break;
} },
ExprKind::Unary(UnDeref, _) => { ExprKind::Unary(UnDeref, _) => {
// `*e` => desugared to `*Deref::deref(&e)`, // `*e` => desugared to `*Deref::deref(&e)`,
// meaning `e` must be referenced. // meaning `e` must be referenced.
// no need to go further up since a method call is involved now. // no need to go further up since a method call is involved now.
needs_check_adjustment = false; needs_check_adjustment = false;
break; break;
} },
_ => break, _ => break,
} }
cur_expr = parent_expr; cur_expr = parent_expr;

View file

@ -7,13 +7,12 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::lint::{LintArray, LintPass, EarlyContext, EarlyLintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::syntax::source_map::Span;
use crate::syntax::symbol::LocalInternedString;
use crate::syntax::ast::*; use crate::syntax::ast::*;
use crate::syntax::attr; use crate::syntax::attr;
use crate::syntax::source_map::Span;
use crate::syntax::symbol::LocalInternedString;
use crate::syntax::visit::{walk_block, walk_expr, walk_pat, Visitor}; use crate::syntax::visit::{walk_block, walk_expr, walk_pat, Visitor};
use crate::utils::{span_lint, span_lint_and_then}; use crate::utils::{span_lint, span_lint_and_then};
@ -116,10 +115,12 @@ impl<'a, 'tcx: 'a, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
fn visit_pat(&mut self, pat: &'tcx Pat) { fn visit_pat(&mut self, pat: &'tcx Pat) {
match pat.node { match pat.node {
PatKind::Ident(_, ident, _) => self.check_name(ident.span, ident.name), PatKind::Ident(_, ident, _) => self.check_name(ident.span, ident.name),
PatKind::Struct(_, ref fields, _) => for field in fields { PatKind::Struct(_, ref fields, _) => {
for field in fields {
if !field.node.is_shorthand { if !field.node.is_shorthand {
self.visit_pat(&field.node.pat); self.visit_pat(&field.node.pat);
} }
}
}, },
_ => walk_pat(self, pat), _ => walk_pat(self, pat),
} }
@ -155,7 +156,10 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
self.0.cx, self.0.cx,
MANY_SINGLE_CHAR_NAMES, MANY_SINGLE_CHAR_NAMES,
span, span,
&format!("{}th binding whose name is just one char", self.0.single_char_names.len()), &format!(
"{}th binding whose name is just one char",
self.0.single_char_names.len()
),
); );
} }
} }
@ -197,26 +201,19 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
} else { } else {
let mut interned_chars = interned_name.chars(); let mut interned_chars = interned_name.chars();
let mut existing_chars = existing_name.interned.chars(); let mut existing_chars = existing_name.interned.chars();
let first_i = interned_chars let first_i = interned_chars.next().expect("we know we have at least one char");
.next() let first_e = existing_chars.next().expect("we know we have at least one char");
.expect("we know we have at least one char");
let first_e = existing_chars
.next()
.expect("we know we have at least one char");
let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric(); let eq_or_numeric = |(a, b): (char, char)| a == b || a.is_numeric() && b.is_numeric();
if eq_or_numeric((first_i, first_e)) { if eq_or_numeric((first_i, first_e)) {
let last_i = interned_chars let last_i = interned_chars.next_back().expect("we know we have at least two chars");
.next_back() let last_e = existing_chars.next_back().expect("we know we have at least two chars");
.expect("we know we have at least two chars");
let last_e = existing_chars
.next_back()
.expect("we know we have at least two chars");
if eq_or_numeric((last_i, last_e)) { if eq_or_numeric((last_i, last_e)) {
if interned_chars if interned_chars
.zip(existing_chars) .zip(existing_chars)
.filter(|&ie| !eq_or_numeric(ie)) .filter(|&ie| !eq_or_numeric(ie))
.count() != 1 .count()
!= 1
{ {
continue; continue;
} }
@ -227,7 +224,8 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
let second_last_e = existing_chars let second_last_e = existing_chars
.next_back() .next_back()
.expect("we know we have at least three chars"); .expect("we know we have at least three chars");
if !eq_or_numeric((second_last_i, second_last_e)) || second_last_i == '_' if !eq_or_numeric((second_last_i, second_last_e))
|| second_last_i == '_'
|| !interned_chars.zip(existing_chars).all(eq_or_numeric) || !interned_chars.zip(existing_chars).all(eq_or_numeric)
{ {
// allowed similarity foo_x, foo_y // allowed similarity foo_x, foo_y
@ -237,13 +235,10 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
split_at = interned_name.char_indices().rev().next().map(|(i, _)| i); split_at = interned_name.char_indices().rev().next().map(|(i, _)| i);
} }
} else { } else {
let second_i = interned_chars let second_i = interned_chars.next().expect("we know we have at least two chars");
.next() let second_e = existing_chars.next().expect("we know we have at least two chars");
.expect("we know we have at least two chars"); if !eq_or_numeric((second_i, second_e))
let second_e = existing_chars || second_i == '_'
.next()
.expect("we know we have at least two chars");
if !eq_or_numeric((second_i, second_e)) || second_i == '_'
|| !interned_chars.zip(existing_chars).all(eq_or_numeric) || !interned_chars.zip(existing_chars).all(eq_or_numeric)
{ {
// allowed similarity x_foo, y_foo // allowed similarity x_foo, y_foo

View file

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::hir::*;
use crate::utils::{match_type, method_chain_args, paths, snippet, span_help_and_lint}; use crate::utils::{match_type, method_chain_args, paths, snippet, span_help_and_lint};
use if_chain::if_chain;
/// **What it does:*** Checks for unnecessary `ok()` in if let. /// **What it does:*** Checks for unnecessary `ok()` in if let.
/// ///

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::{Expr, ExprKind}; use crate::rustc::hir::{Expr, ExprKind};
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
@ -200,7 +199,12 @@ fn check_open_options(cx: &LateContext<'_, '_>, options: &[(OpenOption, Argument
} }
if read && truncate && read_arg && truncate_arg && !(write && write_arg) { if read && truncate && read_arg && truncate_arg && !(write && write_arg) {
span_lint(cx, NONSENSICAL_OPEN_OPTIONS, span, "file opened with \"truncate\" and \"read\""); span_lint(
cx,
NONSENSICAL_OPEN_OPTIONS,
span,
"file opened with \"truncate\" and \"read\"",
);
} }
if append && truncate && append_arg && truncate_arg { if append && truncate && append_arg && truncate_arg {
span_lint( span_lint(

View file

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::hir::*;
use crate::utils::{span_lint, SpanlessEq}; use crate::utils::{span_lint, SpanlessEq};
use if_chain::if_chain;
/// **What it does:** Detects classic underflow/overflow checks. /// **What it does:** Detects classic underflow/overflow checks.
/// ///

View file

@ -7,15 +7,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*; use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::syntax::ast::LitKind; use crate::syntax::ast::LitKind;
use crate::syntax::ptr::P;
use crate::syntax::ext::quote::rt::Span; use crate::syntax::ext::quote::rt::Span;
use crate::syntax::ptr::P;
use crate::utils::{is_direct_expn_of, is_expn_of, match_def_path, opt_def_id, paths, resolve_node, span_lint}; use crate::utils::{is_direct_expn_of, is_expn_of, match_def_path, opt_def_id, paths, resolve_node, span_lint};
use if_chain::if_chain;
/// **What it does:** Checks for missing parameters in `panic!`. /// **What it does:** Checks for missing parameters in `panic!`.
/// ///

View file

@ -7,12 +7,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::hir::*;
use crate::utils::{is_automatically_derived, span_lint}; use crate::utils::{is_automatically_derived, span_lint};
use if_chain::if_chain;
/// **What it does:** Checks for manual re-implementations of `PartialEq::ne`. /// **What it does:** Checks for manual re-implementations of `PartialEq::ne`.
/// ///

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array}; use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
@ -115,7 +114,10 @@ impl EarlyLintPass for Precedence {
expr.span, expr.span,
"unary minus has lower precedence than method call", "unary minus has lower precedence than method call",
"consider adding parentheses to clarify your intent", "consider adding parentheses to clarify your intent",
format!("-({})", snippet_with_applicability(cx, rhs.span, "..", &mut applicability)), format!(
"-({})",
snippet_with_applicability(cx, rhs.span, "..", &mut applicability)
),
applicability, applicability,
); );
}, },

View file

@ -7,22 +7,21 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! Checks for usage of `&Vec[_]` and `&String`. //! Checks for usage of `&Vec[_]` and `&String`.
use std::borrow::Cow;
use crate::rustc::hir::*;
use crate::rustc::hir::QPath; use crate::rustc::hir::QPath;
use crate::rustc::hir::*;
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use if_chain::if_chain;
use crate::rustc::ty; use crate::rustc::ty;
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::NodeId; use crate::syntax::ast::NodeId;
use crate::syntax::source_map::Span; use crate::syntax::source_map::Span;
use crate::syntax_pos::MultiSpan; use crate::syntax_pos::MultiSpan;
use crate::utils::{match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then, walk_ptrs_hir_ty};
use crate::utils::ptr::get_spans; use crate::utils::ptr::get_spans;
use crate::rustc_errors::Applicability; use crate::utils::{match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_then, walk_ptrs_hir_ty};
use if_chain::if_chain;
use std::borrow::Cow;
/// **What it does:** This lint checks for function arguments of type `&String` /// **What it does:** This lint checks for function arguments of type `&String`
/// or `&Vec` unless the references are mutable. It will also suggest you /// or `&Vec` unless the references are mutable. It will also suggest you
@ -57,8 +56,7 @@ use crate::rustc_errors::Applicability;
declare_clippy_lint! { declare_clippy_lint! {
pub PTR_ARG, pub PTR_ARG,
style, style,
"fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \ "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively"
instead, respectively"
} }
/// **What it does:** This lint checks for equality comparisons with `ptr::null` /// **What it does:** This lint checks for equality comparisons with `ptr::null`
@ -71,7 +69,9 @@ declare_clippy_lint! {
/// ///
/// **Example:** /// **Example:**
/// ```rust /// ```rust
/// if x == ptr::null { .. } /// if x == ptr::null {
/// ..
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub CMP_NULL, pub CMP_NULL,
@ -162,12 +162,7 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
let fn_ty = sig.skip_binder(); let fn_ty = sig.skip_binder();
for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() { for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() {
if let ty::Ref( if let ty::Ref(_, ty, MutImmutable) = ty.sty {
_,
ty,
MutImmutable
) = ty.sty
{
if match_type(cx, ty, &paths::VEC) { if match_type(cx, ty, &paths::VEC) {
let mut ty_snippet = None; let mut ty_snippet = None;
if_chain! { if_chain! {
@ -202,10 +197,9 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
for (clonespan, suggestion) in spans { for (clonespan, suggestion) in spans {
db.span_suggestion_with_applicability( db.span_suggestion_with_applicability(
clonespan, clonespan,
&snippet_opt(cx, clonespan).map_or( &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
"change the call to".into(), Cow::Owned(format!("change `{}` to", x))
|x| Cow::Owned(format!("change `{}` to", x)), }),
),
suggestion.into(), suggestion.into(),
Applicability::Unspecified, Applicability::Unspecified,
); );
@ -230,10 +224,9 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
for (clonespan, suggestion) in spans { for (clonespan, suggestion) in spans {
db.span_suggestion_short_with_applicability( db.span_suggestion_short_with_applicability(
clonespan, clonespan,
&snippet_opt(cx, clonespan).map_or( &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
"change the call to".into(), Cow::Owned(format!("change `{}` to", x))
|x| Cow::Owned(format!("change `{}` to", x)), }),
),
suggestion.into(), suggestion.into(),
Applicability::Unspecified, Applicability::Unspecified,
); );
@ -280,7 +273,8 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
if let FunctionRetTy::Return(ref ty) = decl.output { if let FunctionRetTy::Return(ref ty) = decl.output {
if let Some((out, MutMutable, _)) = get_rptr_lm(ty) { if let Some((out, MutMutable, _)) = get_rptr_lm(ty) {
let mut immutables = vec![]; let mut immutables = vec![];
for (_, ref mutbl, ref argspan) in decl.inputs for (_, ref mutbl, ref argspan) in decl
.inputs
.iter() .iter()
.filter_map(|ty| get_rptr_lm(ty)) .filter_map(|ty| get_rptr_lm(ty))
.filter(|&(lt, _, _)| lt.name == out.name) .filter(|&(lt, _, _)| lt.name == out.name)
@ -293,10 +287,16 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
if immutables.is_empty() { if immutables.is_empty() {
return; return;
} }
span_lint_and_then(cx, MUT_FROM_REF, ty.span, "mutable borrow from immutable input(s)", |db| { span_lint_and_then(
cx,
MUT_FROM_REF,
ty.span,
"mutable borrow from immutable input(s)",
|db| {
let ms = MultiSpan::from_spans(immutables); let ms = MultiSpan::from_spans(immutables);
db.span_note(ms, "immutable borrow here"); db.span_note(ms, "immutable borrow here");
}); },
);
} }
} }
} }

View file

@ -7,7 +7,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use crate::rustc::{declare_tool_lint, hir, lint, lint_array}; use crate::rustc::{declare_tool_lint, hir, lint, lint_array};
use crate::rustc_errors::Applicability; use crate::rustc_errors::Applicability;
use crate::utils; use crate::utils;
@ -27,7 +26,9 @@ use std::fmt;
/// let ptr = vec.as_ptr(); /// let ptr = vec.as_ptr();
/// let offset = 1_usize; /// let offset = 1_usize;
/// ///
/// unsafe { ptr.offset(offset as isize); } /// unsafe {
/// ptr.offset(offset as isize);
/// }
/// ``` /// ```
/// ///
/// Could be written: /// Could be written:
@ -37,7 +38,9 @@ use std::fmt;
/// let ptr = vec.as_ptr(); /// let ptr = vec.as_ptr();
/// let offset = 1_usize; /// let offset = 1_usize;
/// ///
/// unsafe { ptr.add(offset); } /// unsafe {
/// ptr.add(offset);
/// }
/// ``` /// ```
declare_clippy_lint! { declare_clippy_lint! {
pub PTR_OFFSET_WITH_CAST, pub PTR_OFFSET_WITH_CAST,
@ -82,7 +85,6 @@ impl<'a, 'tcx> lint::LateLintPass<'a, 'tcx> for Pass {
} else { } else {
utils::span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, &msg); utils::span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, &msg);
} }
} }
} }
@ -119,18 +121,12 @@ fn expr_as_ptr_offset_call<'a, 'tcx>(
} }
// Is the type of the expression a usize? // Is the type of the expression a usize?
fn is_expr_ty_usize<'a, 'tcx>( fn is_expr_ty_usize<'a, 'tcx>(cx: &lint::LateContext<'a, 'tcx>, expr: &hir::Expr) -> bool {
cx: &lint::LateContext<'a, 'tcx>,
expr: &hir::Expr,
) -> bool {
cx.tables.expr_ty(expr) == cx.tcx.types.usize cx.tables.expr_ty(expr) == cx.tcx.types.usize
} }
// Is the type of the expression a raw pointer? // Is the type of the expression a raw pointer?
fn is_expr_ty_raw_ptr<'a, 'tcx>( fn is_expr_ty_raw_ptr<'a, 'tcx>(cx: &lint::LateContext<'a, 'tcx>, expr: &hir::Expr) -> bool {
cx: &lint::LateContext<'a, 'tcx>,
expr: &hir::Expr,
) -> bool {
cx.tables.expr_ty(expr).is_unsafe_ptr() cx.tables.expr_ty(expr).is_unsafe_ptr()
} }

Some files were not shown because too many files have changed in this diff Show more