mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-27 07:00:55 +00:00
Merge pull request #3465 from flip1995/rustfmt
rustfmt everything once and for all
This commit is contained in:
commit
f5831523d3
150 changed files with 3210 additions and 2882 deletions
|
@ -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
|
||||||
|
|
|
@ -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, don’t report any suggestions). You can avoid prolonging
|
tested pass (that is, don’t 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 -->
|
||||||
|
|
||||||
|
|
1
build.rs
1
build.rs
|
@ -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());
|
||||||
|
|
|
@ -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...
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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, &[]))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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("/*")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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`.
|
||||||
|
|
|
@ -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
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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!(==)
|
||||||
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 = ¶ms[0];
|
let param = ¶ms[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 = ¶ms[1];
|
let param = ¶ms[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",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
|
|
|
@ -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
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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 {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
// it’s bad when there is a ‘\n’ after the “else”
|
// it’s 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
|
||||||
|
|
|
@ -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)
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => {},
|
_ => {},
|
||||||
|
|
|
@ -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`.
|
||||||
///
|
///
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -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
|
||||||
///
|
///
|
||||||
|
|
|
@ -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
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
///
|
///
|
||||||
|
|
|
@ -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(..)));
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(<) {
|
if !allowed_lts.contains(<) {
|
||||||
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",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())),
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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, ¬e);
|
span_note_and_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg, expr.span, ¬e);
|
||||||
} 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
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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};
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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(_),
|
||||||
..
|
..
|
||||||
|
|
|
@ -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.
|
||||||
///
|
///
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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(),
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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! {
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
///
|
///
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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.
|
||||||
///
|
///
|
||||||
|
|
|
@ -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!`.
|
||||||
///
|
///
|
||||||
|
|
|
@ -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`.
|
||||||
///
|
///
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -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");
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
Loading…
Reference in a new issue