mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-23 13:13:34 +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:
|
||||
- |
|
||||
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
|
||||
. $HOME/.nvm/nvm.sh
|
||||
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)
|
||||
* [Documentation](#documentation)
|
||||
* [Running test suite](#running-test-suite)
|
||||
* [Running rustfmt](#running-rustfmt)
|
||||
* [Testing manually](#testing-manually)
|
||||
* [Linting Clippy with your local changes](#linting-clippy-with-your-local-changes)
|
||||
* [How Clippy works](#how-clippy-works)
|
||||
* [Fixing nightly build failures](#fixing-build-failures-caused-by-rust)
|
||||
* [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
|
||||
`*.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
|
||||
|
||||
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`
|
||||
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
|
||||
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
|
||||
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 -->
|
||||
|
||||
|
|
1
build.rs
1
build.rs
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
fn main() {
|
||||
// Forward the profile to the main compilation
|
||||
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
|
||||
./util/dev update_lints --check
|
||||
cargo +nightly fmt --all -- --check
|
||||
|
||||
CLIPPY="`pwd`/target/debug/cargo-clippy clippy"
|
||||
# run clippy on its own codebase...
|
||||
|
|
|
@ -7,30 +7,35 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
#![allow(clippy::default_hash_types)]
|
||||
|
||||
use itertools::Itertools;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
use walkdir::WalkDir;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::io::prelude::*;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
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*
|
||||
pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
|
||||
(?P<cat>[a-z_]+)\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*
|
||||
pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
|
||||
"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
|
||||
"#).unwrap();
|
||||
"#
|
||||
)
|
||||
.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();
|
||||
}
|
||||
|
@ -57,13 +62,16 @@ impl Lint {
|
|||
}
|
||||
|
||||
/// 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())
|
||||
}
|
||||
|
||||
/// Returns the lints in a HashMap, grouped by the different lint groups
|
||||
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 {
|
||||
|
@ -73,7 +81,8 @@ impl Lint {
|
|||
|
||||
/// 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> {
|
||||
lints.into_iter()
|
||||
lints
|
||||
.into_iter()
|
||||
.filter_map(|l| {
|
||||
if l.is_internal() || l.deprecation.is_some() {
|
||||
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`.
|
||||
pub fn gen_modules_list(lints: Vec<Lint>) -> Vec<String> {
|
||||
lints.into_iter()
|
||||
lints
|
||||
.into_iter()
|
||||
.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()
|
||||
.map(|module| {
|
||||
format!("pub mod {};", module)
|
||||
})
|
||||
.map(|module| format!("pub mod {};", module))
|
||||
.sorted()
|
||||
}
|
||||
|
||||
|
@ -109,35 +121,31 @@ pub fn gen_changelog_lint_list(lints: Vec<Lint>) -> Vec<String> {
|
|||
} else {
|
||||
Some(format!("[`{}`]: {}#{}", l.name, DOCS_LINK.clone(), l.name))
|
||||
}
|
||||
}).collect()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`.
|
||||
pub fn gen_deprecated(lints: &[Lint]) -> Vec<String> {
|
||||
itertools::flatten(
|
||||
lints
|
||||
.iter()
|
||||
.filter_map(|l| {
|
||||
l.clone().deprecation.and_then(|depr_text| {
|
||||
Some(
|
||||
vec![
|
||||
" store.register_removed(".to_string(),
|
||||
format!(" \"{}\",", l.name),
|
||||
format!(" \"{}\",", depr_text),
|
||||
" );".to_string()
|
||||
]
|
||||
)
|
||||
})
|
||||
})
|
||||
).collect()
|
||||
itertools::flatten(lints.iter().filter_map(|l| {
|
||||
l.clone().deprecation.and_then(|depr_text| {
|
||||
Some(vec![
|
||||
" store.register_removed(".to_string(),
|
||||
format!(" \"{}\",", l.name),
|
||||
format!(" \"{}\",", depr_text),
|
||||
" );".to_string(),
|
||||
])
|
||||
})
|
||||
}))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// 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))
|
||||
}
|
||||
|
||||
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 content = String::new();
|
||||
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
|
||||
// the containing directory:
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
.captures_iter(content)
|
||||
.map(|m| Lint::new(&m["name"], &m["cat"], &m["desc"], None, filename));
|
||||
let deprecated = DEC_DEPRECATED_LINT_RE
|
||||
.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
|
||||
lints.chain(deprecated).collect::<Vec<Lint>>().into_iter()
|
||||
}
|
||||
|
||||
/// 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.
|
||||
// Otherwise we would not collect all the lints, for example in `clippy_lints/src/methods/`.
|
||||
WalkDir::new("../clippy_lints/src")
|
||||
|
@ -184,15 +199,27 @@ pub struct FileChange {
|
|||
///
|
||||
/// See `replace_region_in_text` for documentation of the other options.
|
||||
#[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 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);
|
||||
|
||||
if write_back {
|
||||
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
|
||||
// the file has the proper line endings.
|
||||
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
|
||||
/// * `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.
|
||||
/// * `end` is a `&str` that describes the delimiter line until where the replacement should
|
||||
/// happen. 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.
|
||||
/// The `end` delimiter line is never replaced.
|
||||
/// * `end` is a `&str` that describes the delimiter line until where the replacement should happen.
|
||||
/// 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. The `end`
|
||||
/// delimiter line is never replaced.
|
||||
/// * `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,
|
||||
|
@ -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 result = clippy_dev::replace_region_in_text(
|
||||
/// the_text,
|
||||
/// r#"replace_start"#,
|
||||
/// r#"replace_end"#,
|
||||
/// false,
|
||||
/// || {
|
||||
/// vec!["a different".to_string(), "text".to_string()]
|
||||
/// }
|
||||
/// ).new_lines;
|
||||
/// let result = clippy_dev::replace_region_in_text(the_text, r#"replace_start"#, r#"replace_end"#, false, || {
|
||||
/// vec!["a different".to_string(), "text".to_string()]
|
||||
/// })
|
||||
/// .new_lines;
|
||||
/// 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 mut in_old_region = 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 {
|
||||
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"
|
||||
}
|
||||
"#,
|
||||
"module_name").collect();
|
||||
"module_name",
|
||||
)
|
||||
.collect();
|
||||
|
||||
let expected = vec![
|
||||
Lint::new("ptr_arg", "style", "really long text", None, "module_name"),
|
||||
|
@ -301,7 +328,7 @@ declare_deprecated_lint! {
|
|||
"Deprecated",
|
||||
"`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);
|
||||
|
@ -312,7 +339,7 @@ fn test_replace_region() {
|
|||
let text = "\nabc\n123\n789\ndef\nghi";
|
||||
let expected = FileChange {
|
||||
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, || {
|
||||
vec!["hello world".to_string()]
|
||||
|
@ -325,7 +352,7 @@ fn test_replace_region_with_start() {
|
|||
let text = "\nabc\n123\n789\ndef\nghi";
|
||||
let expected = FileChange {
|
||||
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, || {
|
||||
vec!["hello world".to_string()]
|
||||
|
@ -338,11 +365,9 @@ fn test_replace_region_no_changes() {
|
|||
let text = "123\n456\n789";
|
||||
let expected = FileChange {
|
||||
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, || {
|
||||
vec![]
|
||||
});
|
||||
let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, || vec![]);
|
||||
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_eq2", "Not Deprecated", "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")
|
||||
];
|
||||
let expected = vec![
|
||||
Lint::new("should_assert_eq2", "Not Deprecated", "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",
|
||||
)];
|
||||
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"),
|
||||
];
|
||||
let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
|
||||
expected.insert("group1".to_string(), vec![
|
||||
Lint::new("should_assert_eq", "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(
|
||||
"group1".to_string(),
|
||||
vec![
|
||||
Lint::new("should_assert_eq", "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")],
|
||||
);
|
||||
assert_eq!(expected, Lint::by_lint_group(&lints));
|
||||
}
|
||||
|
||||
|
@ -387,7 +420,7 @@ fn test_gen_changelog_lint_list() {
|
|||
];
|
||||
let expected = vec![
|
||||
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));
|
||||
}
|
||||
|
@ -395,9 +428,21 @@ fn test_gen_changelog_lint_list() {
|
|||
#[test]
|
||||
fn test_gen_deprecated() {
|
||||
let lints = vec![
|
||||
Lint::new("should_assert_eq", "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")
|
||||
Lint::new(
|
||||
"should_assert_eq",
|
||||
"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![
|
||||
" store.register_removed(",
|
||||
|
@ -407,8 +452,11 @@ fn test_gen_deprecated() {
|
|||
" store.register_removed(",
|
||||
" \"another_deprecated\",",
|
||||
" \"will be removed\",",
|
||||
" );"
|
||||
].into_iter().map(String::from).collect();
|
||||
" );",
|
||||
]
|
||||
.into_iter()
|
||||
.map(String::from)
|
||||
.collect();
|
||||
assert_eq!(expected, gen_deprecated(&lints));
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
extern crate clap;
|
||||
extern crate clippy_dev;
|
||||
extern crate regex;
|
||||
|
@ -18,31 +17,33 @@ use clippy_dev::*;
|
|||
#[derive(PartialEq)]
|
||||
enum UpdateMode {
|
||||
Check,
|
||||
Change
|
||||
Change,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let matches = App::new("Clippy developer tooling")
|
||||
.subcommand(
|
||||
SubCommand::with_name("update_lints")
|
||||
.about("Makes sure that:\n \
|
||||
* the lint count in README.md is correct\n \
|
||||
* the changelog contains markdown link references at the bottom\n \
|
||||
* all lint groups include the correct lints\n \
|
||||
* lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
|
||||
* 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)")
|
||||
.about(
|
||||
"Makes sure that:\n \
|
||||
* the lint count in README.md is correct\n \
|
||||
* the changelog contains markdown link references at the bottom\n \
|
||||
* all lint groups include the correct lints\n \
|
||||
* lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
|
||||
* 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("check")
|
||||
.long("check")
|
||||
.help("Checks that util/dev update_lints has been run. Used on CI."),
|
||||
)
|
||||
)
|
||||
.get_matches();
|
||||
),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("update_lints") {
|
||||
if matches.is_present("print-only") {
|
||||
|
@ -62,13 +63,21 @@ fn print_lints() {
|
|||
let grouped_by_lint_group = Lint::by_lint_group(&usable_lints);
|
||||
|
||||
for (lint_group, mut lints) in grouped_by_lint_group {
|
||||
if lint_group == "Deprecated" { continue; }
|
||||
if lint_group == "Deprecated" {
|
||||
continue;
|
||||
}
|
||||
println!("\n## {}", lint_group);
|
||||
|
||||
lints.sort_by_key(|l| l.name.clone());
|
||||
|
||||
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 -->",
|
||||
false,
|
||||
update_mode == &UpdateMode::Change,
|
||||
|| { gen_changelog_lint_list(lint_list.clone()) }
|
||||
).changed;
|
||||
|| gen_changelog_lint_list(lint_list.clone()),
|
||||
)
|
||||
.changed;
|
||||
|
||||
file_change |= replace_region_in_file(
|
||||
"../clippy_lints/src/lib.rs",
|
||||
|
@ -108,8 +118,9 @@ fn update_lints(update_mode: &UpdateMode) {
|
|||
"end deprecated lints",
|
||||
false,
|
||||
update_mode == &UpdateMode::Change,
|
||||
|| { gen_deprecated(&lint_list) }
|
||||
).changed;
|
||||
|| gen_deprecated(&lint_list),
|
||||
)
|
||||
.changed;
|
||||
|
||||
file_change |= replace_region_in_file(
|
||||
"../clippy_lints/src/lib.rs",
|
||||
|
@ -117,8 +128,9 @@ fn update_lints(update_mode: &UpdateMode) {
|
|||
"end lints modules",
|
||||
false,
|
||||
update_mode == &UpdateMode::Change,
|
||||
|| { gen_modules_list(lint_list.clone()) }
|
||||
).changed;
|
||||
|| gen_modules_list(lint_list.clone()),
|
||||
)
|
||||
.changed;
|
||||
|
||||
// Generate lists of lints in the clippy::all lint group
|
||||
file_change |= replace_region_in_file(
|
||||
|
@ -129,16 +141,18 @@ fn update_lints(update_mode: &UpdateMode) {
|
|||
update_mode == &UpdateMode::Change,
|
||||
|| {
|
||||
// clippy::all should only include the following lint groups:
|
||||
let all_group_lints = usable_lints.clone().into_iter().filter(|l| {
|
||||
l.group == "correctness" ||
|
||||
l.group == "style" ||
|
||||
l.group == "complexity" ||
|
||||
l.group == "perf"
|
||||
}).collect();
|
||||
let all_group_lints = usable_lints
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter(|l| {
|
||||
l.group == "correctness" || l.group == "style" || l.group == "complexity" || l.group == "perf"
|
||||
})
|
||||
.collect();
|
||||
|
||||
gen_lint_group_list(all_group_lints)
|
||||
}
|
||||
).changed;
|
||||
},
|
||||
)
|
||||
.changed;
|
||||
|
||||
// Generate the list of lints for all other lint groups
|
||||
for (lint_group, lints) in Lint::by_lint_group(&usable_lints) {
|
||||
|
@ -148,12 +162,16 @@ fn update_lints(update_mode: &UpdateMode) {
|
|||
r#"\]\);"#,
|
||||
false,
|
||||
update_mode == &UpdateMode::Change,
|
||||
|| { gen_lint_group_list(lints.clone()) }
|
||||
).changed;
|
||||
|| gen_lint_group_list(lints.clone()),
|
||||
)
|
||||
.changed;
|
||||
}
|
||||
|
||||
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.");
|
||||
std::process::exit(1);
|
||||
println!(
|
||||
"Not all lints defined properly. \
|
||||
Please run `util/dev update_lints` to make sure all lints are defined properly."
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::utils::span_lint;
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use std::f64::consts as f64;
|
||||
use crate::syntax::ast::{FloatTy, Lit, LitKind};
|
||||
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
|
||||
/// constants which are defined in
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::utils::span_lint;
|
||||
use crate::rustc::hir;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::syntax::source_map::Span;
|
||||
use crate::utils::span_lint;
|
||||
|
||||
/// **What it does:** Checks for plain integer arithmetic.
|
||||
///
|
||||
|
@ -52,7 +51,8 @@ declare_clippy_lint! {
|
|||
#[derive(Copy, Clone, Default)]
|
||||
pub struct Arithmetic {
|
||||
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>,
|
||||
}
|
||||
|
||||
|
@ -124,8 +124,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic {
|
|||
let body_owner = cx.tcx.hir.body_owner(body.id());
|
||||
|
||||
match cx.tcx.hir.body_owner_kind(body_owner) {
|
||||
hir::BodyOwnerKind::Static(_)
|
||||
| hir::BodyOwnerKind::Const => {
|
||||
hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const => {
|
||||
let body_span = cx.tcx.hir.span(body_owner);
|
||||
|
||||
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);
|
||||
}
|
||||
},
|
||||
hir::BodyOwnerKind::Fn => (),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,16 +7,15 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use if_chain::if_chain;
|
||||
use crate::syntax::ast;
|
||||
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`
|
||||
/// patterns.
|
||||
|
@ -217,7 +216,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
|
|||
// a = b commutative_op a
|
||||
// Limited to primitive type as these ops are know to be commutative
|
||||
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 {
|
||||
hir::BinOpKind::Add
|
||||
| hir::BinOpKind::Mul
|
||||
|
|
|
@ -7,27 +7,24 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! checks for attributes
|
||||
|
||||
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::lint::{
|
||||
CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintContext, LintPass,
|
||||
};
|
||||
use crate::rustc::ty::{self, TyCtxt};
|
||||
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::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)]`,
|
||||
/// 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() {
|
||||
"allow" | "warn" | "deny" | "forbid" => {
|
||||
check_clippy_lint_names(cx, items);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
if items.is_empty() || attr.name() != "deprecated" {
|
||||
return;
|
||||
|
@ -254,19 +251,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
|
|||
// and `unused_imports` for `extern crate` items with `macro_use`
|
||||
for lint in lint_list {
|
||||
match item.node {
|
||||
ItemKind::Use(..) => if is_word(lint, "unused_imports")
|
||||
|| is_word(lint, "deprecated") {
|
||||
return
|
||||
ItemKind::Use(..) => {
|
||||
if is_word(lint, "unused_imports") || is_word(lint, "deprecated") {
|
||||
return;
|
||||
}
|
||||
},
|
||||
ItemKind::ExternCrate(..) => {
|
||||
if is_word(lint, "unused_imports")
|
||||
&& skip_unused_imports {
|
||||
return
|
||||
if is_word(lint, "unused_imports") && skip_unused_imports {
|
||||
return;
|
||||
}
|
||||
if is_word(lint, "unused_extern_crates") {
|
||||
return
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
@ -396,14 +393,16 @@ fn is_relevant_expr(tcx: TyCtxt<'_, '_, '_>, tables: &ty::TypeckTables<'_>, expr
|
|||
ExprKind::Block(ref block, _) => is_relevant_block(tcx, tables, block),
|
||||
ExprKind::Ret(Some(ref e)) => is_relevant_expr(tcx, tables, e),
|
||||
ExprKind::Ret(None) | ExprKind::Break(_, None) => false,
|
||||
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)) {
|
||||
!match_def_path(tcx, fun_id, &paths::BEGIN_PANIC)
|
||||
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)) {
|
||||
!match_def_path(tcx, fun_id, &paths::BEGIN_PANIC)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
true
|
||||
},
|
||||
_ => true,
|
||||
}
|
||||
|
@ -435,7 +434,8 @@ fn check_attrs(cx: &LateContext<'_, '_>, span: Span, name: Name, attrs: &[Attrib
|
|||
cx,
|
||||
EMPTY_LINE_AFTER_OUTER_ATTR,
|
||||
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 {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(
|
||||
DEPRECATED_CFG_ATTR,
|
||||
)
|
||||
lint_array!(DEPRECATED_CFG_ATTR,)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,17 +7,16 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::consts::{constant, Constant};
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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::source_map::Span;
|
||||
use crate::utils::{span_lint, span_lint_and_then};
|
||||
use crate::utils::sugg::Sugg;
|
||||
use crate::consts::{constant, Constant};
|
||||
use crate::rustc_errors::Applicability;
|
||||
use crate::utils::{span_lint, span_lint_and_then};
|
||||
use if_chain::if_chain;
|
||||
|
||||
/// **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) {
|
||||
if let ExprKind::Binary(ref op, ref left, ref right) = bit_op.node {
|
||||
if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr {
|
||||
|
@ -185,99 +183,112 @@ 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 {
|
||||
BinOpKind::Eq | BinOpKind::Ne => match bit_op {
|
||||
BinOpKind::BitAnd => if mask_value & cmp_value != cmp_value {
|
||||
if cmp_value != 0 {
|
||||
BinOpKind::BitAnd => {
|
||||
if mask_value & cmp_value != cmp_value {
|
||||
if cmp_value != 0 {
|
||||
span_lint(
|
||||
cx,
|
||||
BAD_BIT_MASK,
|
||||
span,
|
||||
&format!(
|
||||
"incompatible bit mask: `_ & {}` can never be equal to `{}`",
|
||||
mask_value, cmp_value
|
||||
),
|
||||
);
|
||||
}
|
||||
} else if mask_value == 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
|
||||
}
|
||||
},
|
||||
BinOpKind::BitOr => {
|
||||
if mask_value | cmp_value != cmp_value {
|
||||
span_lint(
|
||||
cx,
|
||||
BAD_BIT_MASK,
|
||||
span,
|
||||
&format!(
|
||||
"incompatible bit mask: `_ & {}` can never be equal to `{}`",
|
||||
mask_value,
|
||||
cmp_value
|
||||
"incompatible bit mask: `_ | {}` can never be equal to `{}`",
|
||||
mask_value, cmp_value
|
||||
),
|
||||
);
|
||||
}
|
||||
} else if mask_value == 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
|
||||
},
|
||||
BinOpKind::BitOr => if mask_value | cmp_value != cmp_value {
|
||||
span_lint(
|
||||
cx,
|
||||
BAD_BIT_MASK,
|
||||
span,
|
||||
&format!(
|
||||
"incompatible bit mask: `_ | {}` can never be equal to `{}`",
|
||||
mask_value,
|
||||
cmp_value
|
||||
),
|
||||
);
|
||||
},
|
||||
_ => (),
|
||||
},
|
||||
BinOpKind::Lt | BinOpKind::Ge => match bit_op {
|
||||
BinOpKind::BitAnd => if mask_value < cmp_value {
|
||||
span_lint(
|
||||
cx,
|
||||
BAD_BIT_MASK,
|
||||
span,
|
||||
&format!(
|
||||
"incompatible bit mask: `_ & {}` will always be lower than `{}`",
|
||||
mask_value,
|
||||
cmp_value
|
||||
),
|
||||
);
|
||||
} else if mask_value == 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
|
||||
BinOpKind::BitAnd => {
|
||||
if mask_value < cmp_value {
|
||||
span_lint(
|
||||
cx,
|
||||
BAD_BIT_MASK,
|
||||
span,
|
||||
&format!(
|
||||
"incompatible bit mask: `_ & {}` will always be lower than `{}`",
|
||||
mask_value, cmp_value
|
||||
),
|
||||
);
|
||||
} else if mask_value == 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
|
||||
}
|
||||
},
|
||||
BinOpKind::BitOr => if mask_value >= cmp_value {
|
||||
span_lint(
|
||||
cx,
|
||||
BAD_BIT_MASK,
|
||||
span,
|
||||
&format!(
|
||||
"incompatible bit mask: `_ | {}` will never be lower than `{}`",
|
||||
mask_value,
|
||||
cmp_value
|
||||
),
|
||||
);
|
||||
} else {
|
||||
check_ineffective_lt(cx, span, mask_value, cmp_value, "|");
|
||||
BinOpKind::BitOr => {
|
||||
if mask_value >= cmp_value {
|
||||
span_lint(
|
||||
cx,
|
||||
BAD_BIT_MASK,
|
||||
span,
|
||||
&format!(
|
||||
"incompatible bit mask: `_ | {}` will never be lower than `{}`",
|
||||
mask_value, cmp_value
|
||||
),
|
||||
);
|
||||
} else {
|
||||
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::BitAnd => if mask_value <= cmp_value {
|
||||
span_lint(
|
||||
cx,
|
||||
BAD_BIT_MASK,
|
||||
span,
|
||||
&format!(
|
||||
"incompatible bit mask: `_ & {}` will never be higher than `{}`",
|
||||
mask_value,
|
||||
cmp_value
|
||||
),
|
||||
);
|
||||
} else if mask_value == 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
|
||||
BinOpKind::BitAnd => {
|
||||
if mask_value <= cmp_value {
|
||||
span_lint(
|
||||
cx,
|
||||
BAD_BIT_MASK,
|
||||
span,
|
||||
&format!(
|
||||
"incompatible bit mask: `_ & {}` will never be higher than `{}`",
|
||||
mask_value, cmp_value
|
||||
),
|
||||
);
|
||||
} else if mask_value == 0 {
|
||||
span_lint(cx, BAD_BIT_MASK, span, "&-masking with zero");
|
||||
}
|
||||
},
|
||||
BinOpKind::BitOr => if mask_value > cmp_value {
|
||||
span_lint(
|
||||
cx,
|
||||
BAD_BIT_MASK,
|
||||
span,
|
||||
&format!(
|
||||
"incompatible bit mask: `_ | {}` will always be higher than `{}`",
|
||||
mask_value,
|
||||
cmp_value
|
||||
),
|
||||
);
|
||||
} else {
|
||||
check_ineffective_gt(cx, span, mask_value, cmp_value, "|");
|
||||
BinOpKind::BitOr => {
|
||||
if mask_value > cmp_value {
|
||||
span_lint(
|
||||
cx,
|
||||
BAD_BIT_MASK,
|
||||
span,
|
||||
&format!(
|
||||
"incompatible bit mask: `_ | {}` will always be higher than `{}`",
|
||||
mask_value, cmp_value
|
||||
),
|
||||
);
|
||||
} else {
|
||||
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,
|
||||
&format!(
|
||||
"ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
|
||||
op,
|
||||
m,
|
||||
c
|
||||
op, m, c
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -310,9 +319,7 @@ fn check_ineffective_gt(cx: &LateContext<'_, '_>, span: Span, m: u128, c: u128,
|
|||
span,
|
||||
&format!(
|
||||
"ineffective bit mask: `x {} {}` compared to `{}`, is the same as x compared directly",
|
||||
op,
|
||||
m,
|
||||
c
|
||||
op, m, c
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,10 +7,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::rustc::hir::*;
|
||||
use crate::utils::span_lint;
|
||||
|
||||
/// **What it does:** Checks for usage of blacklisted names for variables, such
|
||||
|
@ -38,9 +37,7 @@ pub struct BlackListedName {
|
|||
|
||||
impl BlackListedName {
|
||||
pub fn new(blacklist: Vec<String>) -> Self {
|
||||
Self {
|
||||
blacklist,
|
||||
}
|
||||
Self { blacklist }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use matches::matches;
|
||||
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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 matches::matches;
|
||||
|
||||
/// **What it does:** Checks for `if` conditions that use blocks to contain an
|
||||
/// expression.
|
||||
|
@ -112,10 +111,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
let span = block
|
||||
.expr
|
||||
.as_ref()
|
||||
.map_or_else(|| block.stmts[0].span, |e| e.span);
|
||||
let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
|
||||
if in_macro(span) || differing_macro_contexts(expr.span, span) {
|
||||
return;
|
||||
}
|
||||
|
@ -134,10 +130,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let mut visitor = ExVisitor {
|
||||
found_block: None,
|
||||
cx,
|
||||
};
|
||||
let mut visitor = ExVisitor { found_block: None, cx };
|
||||
walk_expr(&mut visitor, check);
|
||||
if let Some(block) = visitor.found_block {
|
||||
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
|
||||
// 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::{declare_tool_lint, lint_array};
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::hir::intravisit::*;
|
||||
use crate::rustc_data_structures::thin_vec::ThinVec;
|
||||
use crate::rustc_errors::Applicability;
|
||||
use crate::syntax::ast::{LitKind, NodeId, DUMMY_NODE_ID};
|
||||
use crate::syntax::source_map::{dummy_spanned, Span, DUMMY_SP};
|
||||
use crate::rustc_data_structures::thin_vec::ThinVec;
|
||||
use crate::utils::{in_macro, paths, match_type, snippet_opt, span_lint_and_then, SpanlessEq, get_trait_def_id, implements_trait};
|
||||
use crate::rustc_errors::Applicability;
|
||||
use crate::utils::{
|
||||
get_trait_def_id, implements_trait, in_macro, match_type, paths, snippet_opt, span_lint_and_then, SpanlessEq,
|
||||
};
|
||||
|
||||
/// **What it does:** Checks for boolean expressions that can be written more
|
||||
/// concisely.
|
||||
|
@ -57,10 +58,7 @@ declare_clippy_lint! {
|
|||
}
|
||||
|
||||
// For each pairs, both orders are considered.
|
||||
const METHODS_WITH_NEGATION: [(&str, &str); 2] = [
|
||||
("is_some", "is_none"),
|
||||
("is_err", "is_ok"),
|
||||
];
|
||||
const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")];
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct NonminimalBool;
|
||||
|
@ -134,19 +132,16 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
|
|||
}
|
||||
let negated = match e.node {
|
||||
ExprKind::Binary(binop, ref lhs, ref rhs) => {
|
||||
|
||||
if !implements_ord(self.cx, lhs) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mk_expr = |op| {
|
||||
Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
hir_id: DUMMY_HIR_ID,
|
||||
span: DUMMY_SP,
|
||||
attrs: ThinVec::new(),
|
||||
node: ExprKind::Binary(dummy_spanned(op), lhs.clone(), rhs.clone()),
|
||||
}
|
||||
let mk_expr = |op| Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
hir_id: DUMMY_HIR_ID,
|
||||
span: DUMMY_SP,
|
||||
attrs: ThinVec::new(),
|
||||
node: ExprKind::Binary(dummy_spanned(op), lhs.clone(), rhs.clone()),
|
||||
};
|
||||
match binop.node {
|
||||
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> {
|
||||
match expr.node {
|
||||
ExprKind::Binary(binop, ref lhs, ref rhs) => {
|
||||
|
||||
if !implements_ord(self.cx, lhs) {
|
||||
return None;
|
||||
}
|
||||
|
@ -204,16 +198,19 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
|
|||
BinOpKind::Le => Some(" > "),
|
||||
BinOpKind::Ge => Some(" < "),
|
||||
_ => 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 => {
|
||||
let type_of_receiver = self.cx.tables.expr_ty(&args[0]);
|
||||
if !match_type(self.cx, type_of_receiver, &paths::OPTION) &&
|
||||
!match_type(self.cx, type_of_receiver, &paths::RESULT) {
|
||||
return None;
|
||||
if !match_type(self.cx, type_of_receiver, &paths::OPTION)
|
||||
&& !match_type(self.cx, type_of_receiver, &paths::RESULT)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
METHODS_WITH_NEGATION
|
||||
.iter().cloned()
|
||||
.iter()
|
||||
.cloned()
|
||||
.flat_map(|(a, b)| vec![(a, b), (b, a)])
|
||||
.find(|&(a, _)| a == path.ident.as_str())
|
||||
.and_then(|(_, neg_method)| Some(format!("{}.{}()", self.snip(&args[0])?, neg_method)))
|
||||
|
@ -452,7 +449,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
|
|||
improvements
|
||||
.into_iter()
|
||||
.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;
|
||||
}
|
||||
match e.node {
|
||||
ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => self.bool_expr(e),
|
||||
ExprKind::Unary(UnNot, ref inner) => if self.cx.tables.node_types()[inner.hir_id].is_bool() {
|
||||
self.bool_expr(e);
|
||||
} else {
|
||||
walk_expr(self, e);
|
||||
ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
|
||||
self.bool_expr(e)
|
||||
},
|
||||
ExprKind::Unary(UnNot, ref inner) => {
|
||||
if self.cx.tables.node_types()[inner.hir_id].is_bool() {
|
||||
self.bool_expr(e);
|
||||
} else {
|
||||
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 {
|
||||
let ty = cx.tables.expr_ty(expr);
|
||||
get_trait_def_id(cx, &paths::ORD)
|
||||
.map_or(false, |id| implements_trait(cx, ty, id, &[]))
|
||||
get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]))
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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> {
|
||||
match expr.node {
|
||||
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() {
|
||||
b.expr.as_ref().and_then(|p| get_path_name(p))
|
||||
} else {
|
||||
None
|
||||
ExprKind::Block(ref b, _) => {
|
||||
if b.stmts.is_empty() {
|
||||
b.expr.as_ref().and_then(|p| get_path_name(p))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
ExprKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
|
||||
_ => None,
|
||||
|
|
|
@ -56,7 +56,7 @@ fn is_empty_str(value: &Option<String>) -> bool {
|
|||
match value {
|
||||
None => true,
|
||||
Some(value) if value.is_empty() => true,
|
||||
_ => false
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! Checks for if expressions that contain only an if expression.
|
||||
//!
|
||||
//! For example, the lint would catch:
|
||||
|
@ -24,12 +23,12 @@
|
|||
|
||||
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use if_chain::if_chain;
|
||||
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::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
|
||||
/// 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) {
|
||||
match expr.node {
|
||||
ast::ExprKind::If(ref check, ref then, ref else_) => if let Some(ref else_) = *else_ {
|
||||
check_collapsible_maybe_if_let(cx, else_);
|
||||
} else {
|
||||
check_collapsible_no_if_let(cx, expr, check, then);
|
||||
ast::ExprKind::If(ref check, ref then, ref else_) => {
|
||||
if let Some(ref else_) = *else_ {
|
||||
check_collapsible_maybe_if_let(cx, else_);
|
||||
} else {
|
||||
check_collapsible_no_if_let(cx, expr, check, then);
|
||||
}
|
||||
},
|
||||
ast::ExprKind::IfLet(_, _, _, Some(ref 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 {
|
||||
// We trim all opening braces and whitespaces and then check if the next string is a comment.
|
||||
let trimmed_block_text =
|
||||
snippet_block(cx, expr.span, "..").trim_left_matches(|c: char| c.is_whitespace() || c == '{').to_owned();
|
||||
let trimmed_block_text = snippet_block(cx, expr.span, "..")
|
||||
.trim_left_matches(|c: char| c.is_whitespace() || c == '{')
|
||||
.to_owned();
|
||||
trimmed_block_text.starts_with("//") || trimmed_block_text.starts_with("/*")
|
||||
}
|
||||
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::syntax::ast::*;
|
||||
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
|
||||
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::syntax::ast::*;
|
||||
use crate::utils::{in_macro, snippet, span_lint_and_then};
|
||||
|
||||
/// **What it does:** Checks for constants with an explicit `'static` lifetime.
|
||||
///
|
||||
|
@ -52,16 +51,17 @@ impl StaticConst {
|
|||
TyKind::Array(ref ty, _) => {
|
||||
self.visit_type(&*ty, cx);
|
||||
},
|
||||
TyKind::Tup(ref tup) => for tup_ty in tup {
|
||||
self.visit_type(&*tup_ty, cx);
|
||||
TyKind::Tup(ref tup) => {
|
||||
for tup_ty in tup {
|
||||
self.visit_type(&*tup_ty, cx);
|
||||
}
|
||||
},
|
||||
// This is what we are looking for !
|
||||
TyKind::Rptr(ref optional_lifetime, ref borrow_type) => {
|
||||
// Match the 'static lifetime
|
||||
if let Some(lifetime) = *optional_lifetime {
|
||||
match borrow_type.ty.node {
|
||||
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) |
|
||||
TyKind::Tup(..) => {
|
||||
TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
|
||||
if lifetime.ident.name == "'static" {
|
||||
let snip = snippet(cx, borrow_type.ty.span, "<type>");
|
||||
let sugg = format!("&{}", snip);
|
||||
|
@ -72,7 +72,7 @@ impl StaticConst {
|
|||
"Constants have by default a `'static` lifetime",
|
||||
|db| {
|
||||
db.span_suggestion_with_applicability(
|
||||
ty.span,
|
||||
ty.span,
|
||||
"consider removing `'static`",
|
||||
sugg,
|
||||
Applicability::MachineApplicable, //snippet
|
||||
|
@ -80,8 +80,8 @@ impl StaticConst {
|
|||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
self.visit_type(&*borrow_type.ty, cx);
|
||||
|
|
|
@ -10,21 +10,21 @@
|
|||
|
||||
#![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::*;
|
||||
use crate::rustc::ty::{self, Ty, TyCtxt, Instance};
|
||||
use crate::rustc::lint::LateContext;
|
||||
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::PartialOrd;
|
||||
use std::convert::TryInto;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
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.
|
||||
#[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)) }
|
||||
},
|
||||
(&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,
|
||||
_ => false, // TODO: Are there inter-type equalities?
|
||||
}
|
||||
|
@ -117,7 +119,12 @@ impl Hash for 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) {
|
||||
(&Constant::Str(ref ls), &Constant::Str(ref rs)) => Some(ls.cmp(rs)),
|
||||
(&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::Char(c) => Constant::Char(c),
|
||||
LitKind::Int(n, _) => Constant::Int(n),
|
||||
LitKind::Float(ref is, _) |
|
||||
LitKind::FloatUnsuffixed(ref is) => match ty.sty {
|
||||
LitKind::Float(ref is, _) | LitKind::FloatUnsuffixed(ref is) => match ty.sty {
|
||||
ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
|
||||
ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
|
||||
_ => 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 {
|
||||
tcx: lcx.tcx,
|
||||
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))
|
||||
}
|
||||
|
||||
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) })
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
tcx: lcx.tcx,
|
||||
tables,
|
||||
|
@ -270,9 +287,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
|
|||
/// create `Some(Vec![..])` of all constants, unless there is any
|
||||
/// non-constant part
|
||||
fn multi(&mut self, vec: &[Expr]) -> Option<Vec<Constant>> {
|
||||
vec.iter()
|
||||
.map(|elem| self.expr(elem))
|
||||
.collect::<Option<_>>()
|
||||
vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
|
||||
}
|
||||
|
||||
/// lookup a possibly constant expression from a ExprKind::Path
|
||||
|
@ -331,63 +346,51 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
|
|||
let l = self.expr(left)?;
|
||||
let r = self.expr(right);
|
||||
match (l, r) {
|
||||
(Constant::Int(l), Some(Constant::Int(r))) => {
|
||||
match self.tables.expr_ty(left).sty {
|
||||
ty::Int(ity) => {
|
||||
let l = sext(self.tcx, l, ity);
|
||||
let r = sext(self.tcx, r, ity);
|
||||
let zext = |n: i128| Constant::Int(unsext(self.tcx, n, ity));
|
||||
match op.node {
|
||||
BinOpKind::Add => l.checked_add(r).map(zext),
|
||||
BinOpKind::Sub => l.checked_sub(r).map(zext),
|
||||
BinOpKind::Mul => l.checked_mul(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::Shr => l.checked_shr(
|
||||
r.try_into().expect("invalid shift")
|
||||
).map(zext),
|
||||
BinOpKind::Shl => l.checked_shl(
|
||||
r.try_into().expect("invalid shift")
|
||||
).map(zext),
|
||||
BinOpKind::BitXor => Some(zext(l ^ r)),
|
||||
BinOpKind::BitOr => Some(zext(l | r)),
|
||||
BinOpKind::BitAnd => Some(zext(l & r)),
|
||||
BinOpKind::Eq => Some(Constant::Bool(l == r)),
|
||||
BinOpKind::Ne => Some(Constant::Bool(l != r)),
|
||||
BinOpKind::Lt => Some(Constant::Bool(l < r)),
|
||||
BinOpKind::Le => Some(Constant::Bool(l <= r)),
|
||||
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
|
||||
BinOpKind::Gt => Some(Constant::Bool(l > r)),
|
||||
_ => None,
|
||||
}
|
||||
(Constant::Int(l), Some(Constant::Int(r))) => match self.tables.expr_ty(left).sty {
|
||||
ty::Int(ity) => {
|
||||
let l = sext(self.tcx, l, ity);
|
||||
let r = sext(self.tcx, r, ity);
|
||||
let zext = |n: i128| Constant::Int(unsext(self.tcx, n, ity));
|
||||
match op.node {
|
||||
BinOpKind::Add => l.checked_add(r).map(zext),
|
||||
BinOpKind::Sub => l.checked_sub(r).map(zext),
|
||||
BinOpKind::Mul => l.checked_mul(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::Shr => l.checked_shr(r.try_into().expect("invalid shift")).map(zext),
|
||||
BinOpKind::Shl => l.checked_shl(r.try_into().expect("invalid shift")).map(zext),
|
||||
BinOpKind::BitXor => Some(zext(l ^ r)),
|
||||
BinOpKind::BitOr => Some(zext(l | r)),
|
||||
BinOpKind::BitAnd => Some(zext(l & r)),
|
||||
BinOpKind::Eq => Some(Constant::Bool(l == r)),
|
||||
BinOpKind::Ne => Some(Constant::Bool(l != r)),
|
||||
BinOpKind::Lt => Some(Constant::Bool(l < r)),
|
||||
BinOpKind::Le => Some(Constant::Bool(l <= r)),
|
||||
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
|
||||
BinOpKind::Gt => Some(Constant::Bool(l > r)),
|
||||
_ => None,
|
||||
}
|
||||
ty::Uint(_) => {
|
||||
match op.node {
|
||||
BinOpKind::Add => l.checked_add(r).map(Constant::Int),
|
||||
BinOpKind::Sub => l.checked_sub(r).map(Constant::Int),
|
||||
BinOpKind::Mul => l.checked_mul(r).map(Constant::Int),
|
||||
BinOpKind::Div => l.checked_div(r).map(Constant::Int),
|
||||
BinOpKind::Rem => l.checked_rem(r).map(Constant::Int),
|
||||
BinOpKind::Shr => l.checked_shr(
|
||||
r.try_into().expect("shift too large")
|
||||
).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::BitOr => Some(Constant::Int(l | r)),
|
||||
BinOpKind::BitAnd => Some(Constant::Int(l & r)),
|
||||
BinOpKind::Eq => Some(Constant::Bool(l == r)),
|
||||
BinOpKind::Ne => Some(Constant::Bool(l != r)),
|
||||
BinOpKind::Lt => Some(Constant::Bool(l < r)),
|
||||
BinOpKind::Le => Some(Constant::Bool(l <= r)),
|
||||
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
|
||||
BinOpKind::Gt => Some(Constant::Bool(l > r)),
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
},
|
||||
ty::Uint(_) => match op.node {
|
||||
BinOpKind::Add => l.checked_add(r).map(Constant::Int),
|
||||
BinOpKind::Sub => l.checked_sub(r).map(Constant::Int),
|
||||
BinOpKind::Mul => l.checked_mul(r).map(Constant::Int),
|
||||
BinOpKind::Div => l.checked_div(r).map(Constant::Int),
|
||||
BinOpKind::Rem => l.checked_rem(r).map(Constant::Int),
|
||||
BinOpKind::Shr => l.checked_shr(r.try_into().expect("shift too large")).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::BitOr => Some(Constant::Int(l | r)),
|
||||
BinOpKind::BitAnd => Some(Constant::Int(l & r)),
|
||||
BinOpKind::Eq => Some(Constant::Bool(l == r)),
|
||||
BinOpKind::Ne => Some(Constant::Bool(l != r)),
|
||||
BinOpKind::Lt => Some(Constant::Bool(l < r)),
|
||||
BinOpKind::Le => Some(Constant::Bool(l <= r)),
|
||||
BinOpKind::Ge => Some(Constant::Bool(l >= r)),
|
||||
BinOpKind::Gt => Some(Constant::Bool(l > r)),
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
(Constant::F32(l), Some(Constant::F32(r))) => match op.node {
|
||||
BinOpKind::Add => Some(Constant::F32(l + r)),
|
||||
|
@ -420,7 +423,9 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
|
|||
(l, r) => match (op.node, l, r) {
|
||||
(BinOpKind::And, Constant::Bool(false), _) => Some(Constant::Bool(false)),
|
||||
(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::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)),
|
||||
|
@ -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> {
|
||||
use crate::rustc::mir::interpret::{Scalar, ConstValue};
|
||||
use crate::rustc::mir::interpret::{ConstValue, Scalar};
|
||||
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::Uint(_) | ty::Int(_) => Some(Constant::Int(b)),
|
||||
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(
|
||||
b.try_into().expect("invalid f64 bit representation")
|
||||
b.try_into().expect("invalid f64 bit representation"),
|
||||
))),
|
||||
// FIXME: implement other conversion
|
||||
_ => None,
|
||||
},
|
||||
ConstValue::ScalarPair(Scalar::Ptr(ptr),
|
||||
Scalar::Bits { bits: n, .. }) => match result.ty.sty {
|
||||
ConstValue::ScalarPair(Scalar::Ptr(ptr), Scalar::Bits { bits: n, .. }) => match result.ty.sty {
|
||||
ty::Ref(_, tam, _) => match tam.sty {
|
||||
ty::Str => {
|
||||
let alloc = tcx
|
||||
.alloc_map
|
||||
.lock()
|
||||
.unwrap_memory(ptr.alloc_id);
|
||||
let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
|
||||
let offset = ptr.offset.bytes().try_into().expect("too-large pointer offset");
|
||||
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,
|
||||
}
|
||||
},
|
||||
// FIXME: implement other conversions
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
@ -7,18 +7,17 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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::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::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::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.
|
||||
///
|
||||
|
@ -168,7 +167,8 @@ fn lint_same_cond(cx: &LateContext<'_, '_>, conds: &[&Expr]) {
|
|||
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) {
|
||||
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
|
||||
db.span_note(
|
||||
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 {
|
||||
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.
|
||||
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 {
|
||||
PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => bindings_impl(cx, pat, map),
|
||||
PatKind::TupleStruct(_, ref pats, _) => for pat in pats {
|
||||
bindings_impl(cx, pat, map);
|
||||
PatKind::TupleStruct(_, ref pats, _) => {
|
||||
for pat in pats {
|
||||
bindings_impl(cx, pat, map);
|
||||
}
|
||||
},
|
||||
PatKind::Binding(_, _, ident, ref as_pat) => {
|
||||
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);
|
||||
}
|
||||
},
|
||||
PatKind::Struct(_, ref fields, _) => for pat in fields {
|
||||
bindings_impl(cx, &pat.node.pat, map);
|
||||
PatKind::Struct(_, ref fields, _) => {
|
||||
for pat in fields {
|
||||
bindings_impl(cx, &pat.node.pat, map);
|
||||
}
|
||||
},
|
||||
PatKind::Tuple(ref fields, _) => for pat in fields {
|
||||
bindings_impl(cx, pat, map);
|
||||
PatKind::Tuple(ref fields, _) => {
|
||||
for pat in fields {
|
||||
bindings_impl(cx, pat, map);
|
||||
}
|
||||
},
|
||||
PatKind::Slice(ref lhs, ref mid, ref rhs) => {
|
||||
for pat in lhs {
|
||||
|
@ -316,7 +329,6 @@ fn bindings<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, pat: &Pat) -> FxHashMap<LocalI
|
|||
result
|
||||
}
|
||||
|
||||
|
||||
fn search_same_sequenced<T, Eq>(exprs: &[T], eq: Eq) -> Option<(&T, &T)>
|
||||
where
|
||||
Eq: Fn(&T, &T) -> bool,
|
||||
|
@ -345,10 +357,8 @@ where
|
|||
};
|
||||
}
|
||||
|
||||
let mut map: FxHashMap<_, Vec<&_>> = FxHashMap::with_capacity_and_hasher(
|
||||
exprs.len(),
|
||||
BuildHasherDefault::default()
|
||||
);
|
||||
let mut map: FxHashMap<_, Vec<&_>> =
|
||||
FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
|
||||
|
||||
for expr in exprs {
|
||||
match map.entry(hash(expr)) {
|
||||
|
|
|
@ -7,11 +7,10 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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
|
||||
/// `Iterator`.
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! calculate cyclomatic complexity and warn about overly complex functions
|
||||
|
||||
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::*;
|
||||
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::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]) {
|
||||
self.limit
|
||||
.push_attrs(cx.sess(), attrs, "cyclomatic_complexity");
|
||||
self.limit.push_attrs(cx.sess(), attrs, "cyclomatic_complexity");
|
||||
}
|
||||
fn exit_lint_attrs(&mut self, cx: &LateContext<'a, 'tcx>, attrs: &'tcx [Attribute]) {
|
||||
self.limit
|
||||
.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity");
|
||||
self.limit.pop_attrs(cx.sess(), attrs, "cyclomatic_complexity");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,7 +194,16 @@ impl<'a, 'tcx> Visitor<'tcx> for CCHelper<'a, 'tcx> {
|
|||
|
||||
#[cfg(feature = "debugging")]
|
||||
#[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,
|
||||
"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"))]
|
||||
#[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) {
|
||||
cx.sess().span_note_without_error(
|
||||
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)]`): \
|
||||
cc = {}, arms = {}, div = {}, shorts = {}, returns = {}. \
|
||||
Please file a bug report.",
|
||||
cc,
|
||||
narms,
|
||||
div,
|
||||
shorts,
|
||||
returns
|
||||
cc, narms, div, shorts, returns
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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};
|
||||
|
||||
|
||||
/// **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
|
||||
|
@ -89,6 +87,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DefaultTraitAccess {
|
|||
QPath::TypeRelative(..) => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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::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::utils::paths;
|
||||
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`
|
||||
/// explicitly or vice versa.
|
||||
|
@ -154,18 +153,20 @@ fn check_copy_clone<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, item: &Item, trait_ref
|
|||
ty::Adt(def, _) if def.is_union() => return,
|
||||
|
||||
// Some types are not Clone by default but could be cloned “by hand” if necessary
|
||||
ty::Adt(def, substs) => for variant in &def.variants {
|
||||
for field in &variant.fields {
|
||||
if let ty::FnDef(..) = field.ty(cx.tcx, substs).sty {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for subst in substs {
|
||||
if let ty::subst::UnpackedKind::Type(subst) = subst.unpack() {
|
||||
if let ty::Param(_) = subst.sty {
|
||||
ty::Adt(def, substs) => {
|
||||
for variant in &def.variants {
|
||||
for field in &variant.fields {
|
||||
if let ty::FnDef(..) = field.ty(cx.tcx, substs).sty {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for subst in substs {
|
||||
if let ty::subst::UnpackedKind::Type(subst) = subst.unpack() {
|
||||
if let ty::Param(_) = subst.sty {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use itertools::Itertools;
|
||||
use pulldown_cmark;
|
||||
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::syntax::ast;
|
||||
use crate::syntax::source_map::{BytePos, Span};
|
||||
use crate::syntax_pos::Pos;
|
||||
use crate::utils::span_lint;
|
||||
use itertools::Itertools;
|
||||
use pulldown_cmark;
|
||||
use url::Url;
|
||||
|
||||
/// **What it does:** Checks for the presence of `_`, `::` or camel-case words
|
||||
|
@ -49,9 +48,7 @@ pub struct Doc {
|
|||
|
||||
impl Doc {
|
||||
pub fn new(valid_idents: Vec<String>) -> Self {
|
||||
Self {
|
||||
valid_idents,
|
||||
}
|
||||
Self { valid_idents }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,9 +104,7 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(
|
|||
doc.push('\n');
|
||||
return (
|
||||
doc.to_owned(),
|
||||
vec![
|
||||
(doc.len(), span.with_lo(span.lo() + BytePos(prefix.len() as u32))),
|
||||
],
|
||||
vec![(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;
|
||||
}
|
||||
|
||||
let s = if s.ends_with('s') {
|
||||
&s[..s.len() - 1]
|
||||
} else {
|
||||
s
|
||||
};
|
||||
let s = if s.ends_with('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
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! Lint on unnecessary double comparisons. Some examples:
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
|
@ -51,18 +50,11 @@ impl LintPass for Pass {
|
|||
|
||||
impl<'a, 'tcx> Pass {
|
||||
#[allow(clippy::similar_names)]
|
||||
fn check_binop(
|
||||
&self,
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
op: BinOpKind,
|
||||
lhs: &'tcx Expr,
|
||||
rhs: &'tcx Expr,
|
||||
span: Span,
|
||||
) {
|
||||
fn check_binop(&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()) {
|
||||
(ExprKind::Binary(lb, llhs, lrhs), ExprKind::Binary(rb, rlhs, rrhs)) => {
|
||||
(lb.node, llhs, lrhs, rb.node, rlhs, rrhs)
|
||||
}
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
let mut spanless_eq = SpanlessEq::new(cx).ignore_fn();
|
||||
|
@ -84,13 +76,21 @@ impl<'a, 'tcx> Pass {
|
|||
sugg,
|
||||
applicability,
|
||||
);
|
||||
}}
|
||||
}};
|
||||
}
|
||||
match (op, lkind, rkind) {
|
||||
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => 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!(==),
|
||||
(BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => {
|
||||
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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::syntax::ast::*;
|
||||
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::syntax::ast::*;
|
||||
use crate::utils::{in_macro, span_lint};
|
||||
|
||||
|
||||
/// **What it does:** Checks for unnecessary double parentheses.
|
||||
///
|
||||
/// **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 {
|
||||
ExprKind::Paren(ref in_paren) => match in_paren.node {
|
||||
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 {
|
||||
let param = ¶ms[0];
|
||||
if let ExprKind::Paren(_) = param.node {
|
||||
span_lint(cx, DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses");
|
||||
ExprKind::Call(_, ref params) => {
|
||||
if params.len() == 1 {
|
||||
let param = ¶ms[0];
|
||||
if let ExprKind::Paren(_) = param.node {
|
||||
span_lint(
|
||||
cx,
|
||||
DOUBLE_PARENS,
|
||||
param.span,
|
||||
"Consider removing unnecessary double parentheses",
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
ExprKind::MethodCall(_, ref params) => if params.len() == 2 {
|
||||
let param = ¶ms[1];
|
||||
if let ExprKind::Paren(_) = param.node {
|
||||
span_lint(cx, DOUBLE_PARENS, param.span, "Consider removing unnecessary double parentheses");
|
||||
ExprKind::MethodCall(_, ref params) => {
|
||||
if params.len() == 2 {
|
||||
let param = ¶ms[1];
|
||||
if let ExprKind::Paren(_) = param.node {
|
||||
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
|
||||
// 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::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 if_chain::if_chain;
|
||||
|
||||
/// **What it does:** Checks for calls to `std::mem::drop` with a reference
|
||||
/// instead of an owned value.
|
||||
|
@ -70,9 +69,9 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```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
|
||||
/// // original unaffected
|
||||
/// // original unaffected
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub DROP_COPY,
|
||||
|
@ -97,9 +96,9 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```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
|
||||
/// // original unaffected
|
||||
/// // original unaffected
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub FORGET_COPY,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
|
@ -68,7 +67,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DurationSubsec {
|
|||
expr.span,
|
||||
&format!("Calling `{}()` is more concise than this calculation", suggested_fn),
|
||||
"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,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,10 +7,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! 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::syntax::ast::*;
|
||||
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! lint when there is an enum with no variants
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::rustc::hir::*;
|
||||
use crate::utils::span_lint_and_then;
|
||||
|
||||
/// **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);
|
||||
if let ItemKind::Enum(..) = item.node {
|
||||
let ty = cx.tcx.type_of(did);
|
||||
let adt = ty.ty_adt_def()
|
||||
.expect("already checked whether this is an enum");
|
||||
let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
|
||||
if adt.variants.is_empty() {
|
||||
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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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::utils::SpanlessEq;
|
||||
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`
|
||||
/// or `BTreeMap`.
|
||||
|
@ -26,12 +25,16 @@ use crate::rustc_errors::Applicability;
|
|||
/// **Known problems:** Some false negatives, eg.:
|
||||
/// ```rust
|
||||
/// let k = &key;
|
||||
/// if !m.contains_key(k) { m.insert(k.clone(), v); }
|
||||
/// if !m.contains_key(k) {
|
||||
/// m.insert(k.clone(), v);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// if !m.contains_key(&k) { m.insert(k, v) }
|
||||
/// if !m.contains_key(&k) {
|
||||
/// m.insert(k, v)
|
||||
/// }
|
||||
/// ```
|
||||
/// can be rewritten as:
|
||||
/// ```rust
|
||||
|
@ -60,11 +63,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HashMapLint {
|
|||
// in case of `if !m.contains_key(&k) { m.insert(k, v); }`
|
||||
// we can give a better error message
|
||||
let sole_expr = {
|
||||
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
|
||||
} else {
|
||||
true
|
||||
}
|
||||
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
|
||||
} else {
|
||||
true
|
||||
}
|
||||
};
|
||||
|
||||
let mut visitor = InsertVisitor {
|
||||
|
|
|
@ -7,20 +7,19 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! lint on C-like enums that are `repr(isize/usize)` and have values that
|
||||
//! don't fit into an `i32`
|
||||
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::consts::{miri_to_const, Constant};
|
||||
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::subst::Substs;
|
||||
use crate::rustc::ty::util::IntTypeExt;
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::syntax::ast::{IntTy, UintTy};
|
||||
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
|
||||
/// `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)]
|
||||
/// enum NonPortable {
|
||||
/// X = 0x1_0000_0000,
|
||||
/// Y = 0
|
||||
/// Y = 0,
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
|
@ -68,7 +67,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant {
|
|||
let instance = ty::Instance::new(def_id, substs);
|
||||
let c_id = GlobalId {
|
||||
instance,
|
||||
promoted: None
|
||||
promoted: None,
|
||||
};
|
||||
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)) {
|
||||
|
@ -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()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
},
|
||||
ty::Uint(UintTy::Usize) if val > u128::from(u32::max_value()) => {},
|
||||
_ => continue,
|
||||
}
|
||||
|
|
|
@ -7,11 +7,10 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! lint on `use`ing all variants of an enum
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::hir::def::Def;
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::syntax::ast::NodeId;
|
||||
|
@ -60,12 +59,7 @@ impl EnumGlobUse {
|
|||
}
|
||||
if let ItemKind::Use(ref path, UseKind::Glob) = item.node {
|
||||
if let Def::Enum(_) = path.def {
|
||||
span_lint(
|
||||
cx,
|
||||
ENUM_GLOB_USE,
|
||||
item.span,
|
||||
"don't use glob imports for enum variants",
|
||||
);
|
||||
span_lint(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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! 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::syntax::ast::*;
|
||||
use crate::syntax::source_map::Span;
|
||||
use crate::syntax::symbol::LocalInternedString;
|
||||
use crate::utils::{span_help_and_lint, span_lint};
|
||||
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
|
||||
/// by the same characters.
|
||||
|
@ -139,10 +138,7 @@ fn var2str(var: &Variant) -> LocalInternedString {
|
|||
fn partial_match(pre: &str, name: &str) -> usize {
|
||||
let mut name_iter = name.chars();
|
||||
let _ = name_iter.next_back(); // make sure the name is never fully matched
|
||||
pre.chars()
|
||||
.zip(name_iter)
|
||||
.take_while(|&(l, r)| l == r)
|
||||
.count()
|
||||
pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count()
|
||||
}
|
||||
|
||||
/// Returns the number of chars that match from the end
|
||||
|
@ -171,9 +167,7 @@ fn check_variant(
|
|||
for var in &def.variants {
|
||||
let name = var2str(var);
|
||||
if partial_match(item_name, &name) == item_name_chars
|
||||
&& name.chars()
|
||||
.nth(item_name_chars)
|
||||
.map_or(false, |c| !c.is_lowercase())
|
||||
&& name.chars().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");
|
||||
}
|
||||
|
@ -277,19 +271,26 @@ impl EarlyLintPass for EnumVariantNames {
|
|||
let rmatching = partial_rmatch(mod_camel, &item_camel);
|
||||
let nchars = mod_camel.chars().count();
|
||||
|
||||
let is_word_beginning = |c: char| {
|
||||
c == '_' || c.is_uppercase() || c.is_numeric()
|
||||
};
|
||||
let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
|
||||
|
||||
if matching == nchars {
|
||||
match item_camel.chars().nth(nchars) {
|
||||
Some(c) if is_word_beginning(c) =>
|
||||
span_lint(cx, STUTTER, item.span, "item name starts with its containing module's name"),
|
||||
_ => ()
|
||||
Some(c) if is_word_beginning(c) => span_lint(
|
||||
cx,
|
||||
STUTTER,
|
||||
item.span,
|
||||
"item name starts with its containing module's name",
|
||||
),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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::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
|
||||
/// 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::Shr => (cx.tcx.lang_items().shr_trait(), false),
|
||||
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 {
|
||||
#[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| {
|
||||
let lsnip = snippet(cx, l.span, "...").to_string();
|
||||
db.span_suggestion_with_applicability(
|
||||
|
@ -132,7 +138,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
|
|||
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(
|
||||
cx,
|
||||
OP_REF,
|
||||
|
@ -154,7 +163,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
|
|||
(&ExprKind::AddrOf(_, ref l), _) => {
|
||||
let lty = cx.tables.expr_ty(l);
|
||||
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| {
|
||||
let lsnip = snippet(cx, l.span, "...").to_string();
|
||||
db.span_suggestion_with_applicability(
|
||||
|
@ -170,7 +181,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
|
|||
(_, &ExprKind::AddrOf(_, ref r)) => {
|
||||
let rty = cx.tables.expr_ty(r);
|
||||
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| {
|
||||
let rsnip = snippet(cx, r.span, "...").to_string();
|
||||
db.span_suggestion_with_applicability(
|
||||
|
@ -189,10 +202,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EqOp {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
fn is_valid_operator(op: BinOp) -> bool {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::consts::{constant_simple, Constant};
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
|
@ -25,7 +24,9 @@ use crate::utils::{in_macro, span_lint};
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// 0 / x; 0 * x; x & 0
|
||||
/// 0 / x;
|
||||
/// 0 * x;
|
||||
/// x & 0
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub ERASING_OP,
|
||||
|
|
|
@ -7,16 +7,15 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::hir::intravisit as visit;
|
||||
use crate::rustc::hir::*;
|
||||
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::mem_categorization::{cmt_, Categorization};
|
||||
use crate::rustc::ty::{self, Ty};
|
||||
use crate::rustc::ty::layout::LayoutOf;
|
||||
use crate::rustc::ty::{self, Ty};
|
||||
use crate::rustc::util::nodemap::NodeSet;
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::syntax::ast::NodeId;
|
||||
use crate::syntax::source_map::Span;
|
||||
use crate::utils::span_lint;
|
||||
|
@ -65,7 +64,6 @@ impl LintPass for Pass {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
||||
|
||||
fn check_fn(
|
||||
&mut self,
|
||||
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 {
|
||||
match loan_cause {
|
||||
// x.foo()
|
||||
|
|
|
@ -7,17 +7,15 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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::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::utils::{is_adjusted, iter_input_pats, snippet_opt, span_lint_and_then};
|
||||
|
||||
pub struct EtaPass;
|
||||
|
||||
|
||||
/// **What it does:** Checks for closures which just call another function where
|
||||
/// the function can be called directly. `unsafe` functions or calls where types
|
||||
/// get adjusted are ignored.
|
||||
|
@ -52,8 +50,10 @@ impl LintPass for EtaPass {
|
|||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EtaPass {
|
||||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
match expr.node {
|
||||
ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => for arg in args {
|
||||
check_closure(cx, arg)
|
||||
ExprKind::Call(_, ref args) | ExprKind::MethodCall(_, _, ref args) => {
|
||||
for arg in args {
|
||||
check_closure(cx, arg)
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::ty;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::ty;
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use if_chain::if_chain;
|
||||
use crate::syntax::ast;
|
||||
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
|
||||
/// 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:**
|
||||
/// ```rust
|
||||
/// let mut x = 0;
|
||||
/// let a = {x = 1; 1} + x;
|
||||
/// let a = {
|
||||
/// x = 1;
|
||||
/// 1
|
||||
/// } + x;
|
||||
/// // Unclear whether a is 1 or 2.
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
|
@ -74,17 +76,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence {
|
|||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
// Find a write to a local variable.
|
||||
match expr.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 path.segments.len() == 1 {
|
||||
if let def::Def::Local(var) = cx.tables.qpath_def(qpath, lhs.hir_id) {
|
||||
let mut visitor = ReadVisitor {
|
||||
cx,
|
||||
var,
|
||||
write_expr: expr,
|
||||
last_expr: expr,
|
||||
};
|
||||
check_for_unsequenced_reads(&mut visitor);
|
||||
ExprKind::Assign(ref lhs, _) | ExprKind::AssignOp(_, ref lhs, _) => {
|
||||
if let ExprKind::Path(ref qpath) = lhs.node {
|
||||
if let QPath::Resolved(_, ref path) = *qpath {
|
||||
if path.segments.len() == 1 {
|
||||
if let def::Def::Local(var) = cx.tables.qpath_def(qpath, lhs.hir_id) {
|
||||
let mut visitor = ReadVisitor {
|
||||
cx,
|
||||
var,
|
||||
write_expr: expr,
|
||||
last_expr: expr,
|
||||
};
|
||||
check_for_unsequenced_reads(&mut visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,12 +99,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EvalOrderDependence {
|
|||
fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx Stmt) {
|
||||
match stmt.node {
|
||||
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 {
|
||||
if let Local {
|
||||
init: Some(ref e), ..
|
||||
} = **local
|
||||
{
|
||||
DivergenceVisitor { cx }.visit_expr(e);
|
||||
StmtKind::Decl(ref d, _) => {
|
||||
if let DeclKind::Local(ref local) = d.node {
|
||||
if let Local { init: Some(ref e), .. } = **local {
|
||||
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
|
||||
/// the write such that
|
||||
///
|
||||
/// * evaluating the ancestor necessarily evaluates both the read and the write
|
||||
/// (for example, `&x` and `|| x = 1` don't necessarily evaluate `x`), and
|
||||
/// * evaluating the ancestor necessarily evaluates both the read and the write (for example, `&x`
|
||||
/// and `|| x = 1` don't necessarily evaluate `x`), and
|
||||
///
|
||||
/// * which one is evaluated first depends on the order of sub-expression
|
||||
/// evaluation. Blocks, `if`s, loops, `match`es, and the short-circuiting
|
||||
/// logical operators are considered to have a defined evaluation order.
|
||||
/// * which one is evaluated first depends on the order of sub-expression evaluation. Blocks, `if`s,
|
||||
/// loops, `match`es, and the short-circuiting logical operators are considered to have a defined
|
||||
/// evaluation order.
|
||||
///
|
||||
/// When such a read is found, the lint is triggered.
|
||||
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 {
|
||||
ExprKind::Array(_) |
|
||||
ExprKind::Tup(_) |
|
||||
ExprKind::MethodCall(..) |
|
||||
ExprKind::Call(_, _) |
|
||||
ExprKind::Assign(_, _) |
|
||||
ExprKind::Index(_, _) |
|
||||
ExprKind::Repeat(_, _) |
|
||||
ExprKind::Struct(_, _, _) => {
|
||||
ExprKind::Array(_)
|
||||
| ExprKind::Tup(_)
|
||||
| ExprKind::MethodCall(..)
|
||||
| ExprKind::Call(_, _)
|
||||
| ExprKind::Assign(_, _)
|
||||
| ExprKind::Index(_, _)
|
||||
| ExprKind::Repeat(_, _)
|
||||
| ExprKind::Struct(_, _, _) => {
|
||||
walk_expr(vis, expr);
|
||||
},
|
||||
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(_, _, _, _, _) => {
|
||||
// Either
|
||||
//
|
||||
// * `var` is defined in the closure body, in which case we've
|
||||
// reached the top of the enclosing function and can stop, or
|
||||
// * `var` is defined in the closure body, in which case we've reached the top of the enclosing
|
||||
// function and can stop, or
|
||||
//
|
||||
// * `var` is captured by the closure, in which case, because
|
||||
// evaluating a closure does not evaluate its body, we don't
|
||||
// necessarily have a write, so we need to stop to avoid
|
||||
// generating false positives.
|
||||
// * `var` is captured by the closure, in which case, because evaluating a closure does not evaluate
|
||||
// its body, we don't necessarily have a write, so we need to stop to avoid generating false
|
||||
// positives.
|
||||
//
|
||||
// This is also the only place we need to stop early (grrr).
|
||||
return StopEarly::Stop;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::ty::TyKind;
|
||||
|
@ -32,12 +31,12 @@ use std::fmt;
|
|||
///
|
||||
/// ```rust
|
||||
/// // Bad
|
||||
/// let v: f32 = 0.123_456_789_9;
|
||||
/// println!("{}", v); // 0.123_456_789
|
||||
/// let v: f32 = 0.123_456_789_9;
|
||||
/// println!("{}", v); // 0.123_456_789
|
||||
///
|
||||
/// // Good
|
||||
/// let v: f64 = 0.123_456_789_9;
|
||||
/// println!("{}", v); // 0.123_456_789_9
|
||||
/// let v: f64 = 0.123_456_789_9;
|
||||
/// println!("{}", v); // 0.123_456_789_9
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub EXCESSIVE_PRECISION,
|
||||
|
@ -82,7 +81,7 @@ impl ExcessivePrecision {
|
|||
let max = max_digits(fty);
|
||||
let sym_str = sym.as_str();
|
||||
if dot_zero_exclusion(&sym_str) {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
// Try to bail out if the float is for sure fine.
|
||||
// If its within the 2 decimal digits of being out of precision we
|
||||
|
@ -116,9 +115,7 @@ impl ExcessivePrecision {
|
|||
/// Ex 1_000_000_000.
|
||||
fn dot_zero_exclusion(s: &str) -> bool {
|
||||
if let Some(after_dec) = s.split('.').nth(1) {
|
||||
let mut decpart = after_dec
|
||||
.chars()
|
||||
.take_while(|c| *c != 'e' || *c != 'E');
|
||||
let mut decpart = after_dec.chars().take_while(|c| *c != 'e' || *c != 'E');
|
||||
|
||||
match decpart.next() {
|
||||
Some('0') => decpart.count() == 0,
|
||||
|
@ -169,7 +166,9 @@ impl FloatFormat {
|
|||
.unwrap_or(FloatFormat::Normal)
|
||||
}
|
||||
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 {
|
||||
FloatFormat::LowerExp => format!("{:e}", f),
|
||||
FloatFormat::UpperExp => format!("{:E}", f),
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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::{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
|
||||
/// replaced with `(e)print!()` / `(e)println!()`
|
||||
|
@ -30,8 +29,7 @@ use crate::utils::opt_def_id;
|
|||
declare_clippy_lint! {
|
||||
pub EXPLICIT_WRITE,
|
||||
complexity,
|
||||
"using the `write!()` family of functions instead of the `print!()` family \
|
||||
of functions, when using the latter would work"
|
||||
"using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work"
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::ty;
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
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::{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()`
|
||||
///
|
||||
|
@ -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>) {
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use crate::rustc::hir::*;
|
||||
|
||||
struct FindPanicUnwrap<'a, 'tcx: 'a> {
|
||||
tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
|
|
@ -7,16 +7,18 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
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::{declare_tool_lint, lint_array};
|
||||
use crate::rustc_errors::Applicability;
|
||||
use crate::syntax::ast::LitKind;
|
||||
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::rustc_errors::Applicability;
|
||||
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 if_chain::if_chain;
|
||||
|
||||
/// **What it does:** Checks for the use of `format!("string literal with no
|
||||
/// argument")` and `format!("{}", foo)` where `foo` is a string.
|
||||
|
@ -92,17 +94,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
}
|
||||
},
|
||||
// `format!("foo")` expansion contains `match () { () => [], }`
|
||||
ExprKind::Match(ref matchee, _, _) => if let ExprKind::Tup(ref tup) = matchee.node {
|
||||
if tup.is_empty() {
|
||||
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| {
|
||||
db.span_suggestion_with_applicability(
|
||||
span,
|
||||
"consider using .to_string()",
|
||||
sugg,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
});
|
||||
ExprKind::Match(ref matchee, _, _) => {
|
||||
if let ExprKind::Tup(ref tup) = matchee.node {
|
||||
if tup.is_empty() {
|
||||
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| {
|
||||
db.span_suggestion_with_applicability(
|
||||
span,
|
||||
"consider using .to_string()",
|
||||
sugg,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
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::utils::{differing_macro_contexts, in_macro, snippet_opt, span_note_and_lint};
|
||||
|
||||
/// **What it does:** Checks for use of the non-existent `=*`, `=!` and `=-`
|
||||
/// operators.
|
||||
|
@ -78,7 +77,6 @@ declare_clippy_lint! {
|
|||
"possible missing comma in array"
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Formatting;
|
||||
|
||||
|
@ -96,8 +94,8 @@ impl EarlyLintPass for Formatting {
|
|||
fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
|
||||
for w in block.stmts.windows(2) {
|
||||
match (&w[0].node, &w[1].node) {
|
||||
(&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::Expr(ref second))
|
||||
| (&ast::StmtKind::Expr(ref first), &ast::StmtKind::Semi(ref 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
|
||||
// it’s bad when there is a ‘\n’ after the “else”
|
||||
if let Some(else_snippet) = snippet_opt(cx, else_span) {
|
||||
let else_pos = else_snippet
|
||||
.find("else")
|
||||
.expect("there must be a `else` here");
|
||||
let else_pos = else_snippet.find("else").expect("there must be a `else` here");
|
||||
|
||||
if else_snippet[else_pos..].contains('\n') {
|
||||
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 {
|
||||
// &, *, -
|
||||
bin_op == ast::BinOpKind::And
|
||||
|| bin_op == ast::BinOpKind::Mul
|
||||
|| bin_op == ast::BinOpKind::Sub
|
||||
bin_op == ast::BinOpKind::And || bin_op == ast::BinOpKind::Mul || bin_op == ast::BinOpKind::Sub
|
||||
}
|
||||
|
||||
/// 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.
|
||||
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()
|
||||
{
|
||||
// where the else would be
|
||||
|
|
|
@ -7,19 +7,18 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use matches::matches;
|
||||
use crate::rustc::hir::intravisit;
|
||||
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::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::syntax::ast;
|
||||
use crate::rustc_target::spec::abi::Abi;
|
||||
use crate::syntax::ast;
|
||||
use crate::syntax::source_map::Span;
|
||||
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.
|
||||
///
|
||||
|
@ -31,8 +30,9 @@ use crate::utils::{iter_input_pats, span_lint, type_is_unsafe_function};
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b:
|
||||
/// f32) { .. }
|
||||
/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub TOO_MANY_ARGUMENTS,
|
||||
|
@ -58,7 +58,9 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// pub fn foo(x: *const u8) { println!("{}", unsafe { *x }); }
|
||||
/// pub fn foo(x: *const u8) {
|
||||
/// println!("{}", unsafe { *x });
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub NOT_UNSAFE_PTR_ARG_DEREF,
|
||||
|
@ -73,9 +75,7 @@ pub struct Functions {
|
|||
|
||||
impl Functions {
|
||||
pub fn new(threshold: u64) -> Self {
|
||||
Self {
|
||||
threshold,
|
||||
}
|
||||
Self { threshold }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,8 +111,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
|
|||
if !is_impl {
|
||||
// don't lint extern functions decls, it's not their fault either
|
||||
match kind {
|
||||
hir::intravisit::FnKind::Method(_, &hir::MethodSig { header: hir::FnHeader { abi: Abi::Rust, .. }, .. }, _, _) |
|
||||
hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => self.check_arg_number(cx, decl, span),
|
||||
hir::intravisit::FnKind::Method(
|
||||
_,
|
||||
&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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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::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.
|
||||
///
|
||||
|
@ -101,22 +102,25 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion {
|
|||
}
|
||||
},
|
||||
|
||||
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 match_def_path(cx.tcx, def_id, &paths::FROM_FROM[..]) {
|
||||
let a = cx.tables.expr_ty(e);
|
||||
let b = cx.tables.expr_ty(&args[0]);
|
||||
if same_tys(cx, a, b) {
|
||||
let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned();
|
||||
let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
|
||||
span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| {
|
||||
db.span_suggestion_with_applicability(
|
||||
e.span,
|
||||
&sugg_msg,
|
||||
sugg,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
});
|
||||
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 match_def_path(cx.tcx, def_id, &paths::FROM_FROM[..]) {
|
||||
let a = cx.tables.expr_ty(e);
|
||||
let b = cx.tables.expr_ty(&args[0]);
|
||||
if same_tys(cx, a, b) {
|
||||
let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned();
|
||||
let sugg_msg =
|
||||
format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
|
||||
span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| {
|
||||
db.span_suggestion_with_applicability(
|
||||
e.span,
|
||||
&sugg_msg,
|
||||
sugg,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::consts::{constant_simple, 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::source_map::Span;
|
||||
use crate::utils::{in_macro, snippet, span_lint, unsext, clip};
|
||||
use crate::rustc::ty;
|
||||
use crate::utils::{clip, in_macro, snippet, span_lint, unsext};
|
||||
|
||||
/// **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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! lint on if branches that could be swapped so no `!` operation is necessary
|
||||
//! 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::syntax::ast::*;
|
||||
|
||||
|
|
|
@ -7,18 +7,17 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! lint on indexing and slicing operations
|
||||
|
||||
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::higher;
|
||||
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
|
||||
/// index.
|
||||
|
@ -29,7 +28,7 @@ use crate::syntax::ast::RangeLimits;
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// let x = [1,2,3,4];
|
||||
/// let x = [1, 2, 3, 4];
|
||||
///
|
||||
/// // Bad
|
||||
/// x[9];
|
||||
|
@ -108,7 +107,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IndexingSlicing {
|
|||
if let ExprKind::Index(ref array, ref index) = &expr.node {
|
||||
let ty = cx.tables.expr_ty(array);
|
||||
if let Some(range) = higher::range(cx, index) {
|
||||
|
||||
// Ranged indexes, i.e. &x[n..m], &x[n..], &x[..n] and &x[..]
|
||||
if let ty::Array(_, s) = ty.sty {
|
||||
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.
|
||||
};
|
||||
|
||||
utils::span_help_and_lint(
|
||||
cx,
|
||||
INDEXING_SLICING,
|
||||
expr.span,
|
||||
"slicing may panic.",
|
||||
help_msg,
|
||||
);
|
||||
utils::span_help_and_lint(cx, INDEXING_SLICING, expr.span, "slicing may panic.", help_msg);
|
||||
} else {
|
||||
// Catchall non-range index, i.e. [n] or [n << m]
|
||||
if let ty::Array(..) = ty.sty {
|
||||
|
@ -189,23 +181,21 @@ fn to_const_range<'a, 'tcx>(
|
|||
range: Range<'_>,
|
||||
array_size: u128,
|
||||
) -> (Option<u128>, Option<u128>) {
|
||||
let s = range
|
||||
.start
|
||||
.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
|
||||
let s = range.start.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
|
||||
let start = match s {
|
||||
Some(Some(Constant::Int(x))) => Some(x),
|
||||
Some(_) => None,
|
||||
None => Some(0),
|
||||
};
|
||||
|
||||
let e = range
|
||||
.end
|
||||
.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
|
||||
let e = range.end.map(|expr| constant(cx, cx.tables, expr).map(|(c, _)| c));
|
||||
let end = match e {
|
||||
Some(Some(Constant::Int(x))) => if range.limits == RangeLimits::Closed {
|
||||
Some(x + 1)
|
||||
} else {
|
||||
Some(x)
|
||||
Some(Some(Constant::Int(x))) => {
|
||||
if range.limits == RangeLimits::Closed {
|
||||
Some(x + 1)
|
||||
} else {
|
||||
Some(x)
|
||||
}
|
||||
},
|
||||
Some(_) => None,
|
||||
None => Some(array_size),
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use super::utils::{get_arg_name, match_var, remove_blocks, snippet_with_applicability, span_lint_and_sugg};
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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]),
|
||||
Any => is_infinite(cx, &args[0]).or(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 {
|
||||
|
@ -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::Box(ref e) | ExprKind::AddrOf(_, ref e) => is_infinite(cx, e),
|
||||
ExprKind::Call(ref path, _) => if let ExprKind::Path(ref qpath) = path.node {
|
||||
match_qpath(qpath, &paths::REPEAT).into()
|
||||
} else {
|
||||
Finite
|
||||
ExprKind::Call(ref path, _) => {
|
||||
if let ExprKind::Path(ref qpath) = path.node {
|
||||
match_qpath(qpath, &paths::REPEAT).into()
|
||||
} else {
|
||||
Finite
|
||||
}
|
||||
},
|
||||
ExprKind::Struct(..) => higher::range(cx, expr)
|
||||
.map_or(false, |r| r.end.is_none())
|
||||
.into(),
|
||||
ExprKind::Struct(..) => higher::range(cx, expr).map_or(false, |r| r.end.is_none()).into(),
|
||||
_ => 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() {
|
||||
return is_infinite(cx, l)
|
||||
.and(is_infinite(cx, r))
|
||||
.and(MaybeInfinite);
|
||||
ExprKind::Binary(op, ref l, ref r) => {
|
||||
if op.node.is_comparison() {
|
||||
return is_infinite(cx, l).and(is_infinite(cx, r)).and(MaybeInfinite);
|
||||
}
|
||||
}, // TODO: ExprKind::Loop + Match
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
@ -7,16 +7,15 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! lint on inherent implementations
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::rustc_data_structures::fx::FxHashMap;
|
||||
use std::default::Default;
|
||||
use crate::syntax_pos::Span;
|
||||
use crate::utils::span_lint_and_then;
|
||||
use std::default::Default;
|
||||
|
||||
/// **What it does:** Checks for multiple inherent implementations of a struct
|
||||
///
|
||||
|
@ -56,7 +55,9 @@ pub struct Pass {
|
|||
|
||||
impl Default for Pass {
|
||||
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
|
||||
.iter()
|
||||
.filter_map(|impl_def| self.impls.get(impl_def))
|
||||
.filter_map(|(span, generics)| if generics.params.len() == 0 {
|
||||
Some(span)
|
||||
} else {
|
||||
None
|
||||
});
|
||||
.filter_map(|(span, generics)| if generics.params.len() == 0 { Some(span) } else { None });
|
||||
if let Some(initial_span) = impl_spans.nth(0) {
|
||||
impl_spans.for_each(|additional_span| {
|
||||
span_lint_and_then(
|
||||
|
@ -101,10 +98,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
*additional_span,
|
||||
"Multiple implementations of this structure",
|
||||
|db| {
|
||||
db.span_note(
|
||||
*initial_span,
|
||||
"First implementation here",
|
||||
);
|
||||
db.span_note(*initial_span, "First implementation here");
|
||||
},
|
||||
)
|
||||
})
|
||||
|
|
|
@ -7,16 +7,15 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! checks for `#[inline]` on trait methods without bodies
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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::utils::span_lint_and_then;
|
||||
use crate::utils::sugg::DiagnosticBuilderExt;
|
||||
use crate::rustc_errors::Applicability;
|
||||
|
||||
/// **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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! lint on blocks unnecessarily using >= with a + 1 or - 1
|
||||
|
||||
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
|
||||
|
@ -162,14 +161,20 @@ impl IntPlusOne {
|
|||
}
|
||||
|
||||
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| {
|
||||
db.span_suggestion_with_applicability(
|
||||
block.span,
|
||||
"change `>= y + 1` to `> y` as shown",
|
||||
recommendation,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
});
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
INT_PLUS_ONE,
|
||||
block.span,
|
||||
"Unnecessary `>= y + 1` or `x - 1 >=`",
|
||||
|db| {
|
||||
db.span_suggestion_with_applicability(
|
||||
block.span,
|
||||
"change `>= y + 1` to `> y` as shown",
|
||||
recommendation,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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::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 if_chain::if_chain;
|
||||
|
||||
/// **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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! lint when items are used after statements
|
||||
|
||||
use matches::matches;
|
||||
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::syntax::ast::*;
|
||||
use crate::utils::{in_macro, span_lint};
|
||||
use matches::matches;
|
||||
|
||||
/// **What it does:** Checks for items declared after some statement in a block.
|
||||
///
|
||||
|
@ -59,7 +58,8 @@ impl EarlyLintPass for ItemsAfterStatements {
|
|||
}
|
||||
|
||||
// skip initial items
|
||||
let stmts = item.stmts
|
||||
let stmts = item
|
||||
.stmts
|
||||
.iter()
|
||||
.map(|stmt| &stmt.node)
|
||||
.skip_while(|s| matches!(**s, StmtKind::Item(..)));
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! 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::utils::{snippet_opt, span_lint_and_then};
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::ty::layout::LayoutOf;
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
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
|
||||
/// `enum`s.
|
||||
|
@ -29,8 +28,8 @@ use crate::rustc_errors::Applicability;
|
|||
/// **Example:**
|
||||
/// ```rust
|
||||
/// enum Test {
|
||||
/// A(i32),
|
||||
/// B([i32; 8000]),
|
||||
/// A(i32),
|
||||
/// B([i32; 8000]),
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
|
@ -63,8 +62,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant {
|
|||
let did = cx.tcx.hir.local_def_id(item.id);
|
||||
if let ItemKind::Enum(ref def, _) = item.node {
|
||||
let ty = cx.tcx.type_of(did);
|
||||
let adt = ty.ty_adt_def()
|
||||
.expect("already checked whether this is an enum");
|
||||
let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
|
||||
|
||||
let mut smallest_variant: Option<(_, _)> = None;
|
||||
let mut largest_variant: Option<(_, _)> = None;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::def_id::DefId;
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
|
@ -32,19 +31,27 @@ use crate::utils::{get_item_name, in_macro, snippet_with_applicability, span_lin
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// if x.len() == 0 { .. }
|
||||
/// if y.len() != 0 { .. }
|
||||
/// if x.len() == 0 {
|
||||
/// ..
|
||||
/// }
|
||||
/// if y.len() != 0 {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
/// instead use
|
||||
/// ```rust
|
||||
/// if x.len().is_empty() { .. }
|
||||
/// if !y.len().is_empty() { .. }
|
||||
/// if x.len().is_empty() {
|
||||
/// ..
|
||||
/// }
|
||||
/// if !y.len().is_empty() {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub LEN_ZERO,
|
||||
style,
|
||||
"checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \
|
||||
could be used instead"
|
||||
pub LEN_ZERO,
|
||||
style,
|
||||
"checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` \
|
||||
could be used instead"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for items that implement `.len()` but not
|
||||
|
@ -61,7 +68,9 @@ declare_clippy_lint! {
|
|||
/// **Example:**
|
||||
/// ```rust
|
||||
/// impl X {
|
||||
/// pub fn len(&self) -> usize { .. }
|
||||
/// pub fn len(&self) -> usize {
|
||||
/// ..
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
|
@ -125,14 +134,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LenZero {
|
|||
|
||||
fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items: &[TraitItemRef]) {
|
||||
fn is_named_self(cx: &LateContext<'_, '_>, item: &TraitItemRef, name: &str) -> bool {
|
||||
item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind {
|
||||
has_self && {
|
||||
let did = cx.tcx.hir.local_def_id(item.id.node_id);
|
||||
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
|
||||
item.ident.name == name
|
||||
&& if let AssociatedItemKind::Method { has_self } = item.kind {
|
||||
has_self && {
|
||||
let did = cx.tcx.hir.local_def_id(item.id.node_id);
|
||||
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// fill the set with current and super traits
|
||||
|
@ -153,7 +163,9 @@ fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items
|
|||
.iter()
|
||||
.flat_map(|&i| cx.tcx.associated_items(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
|
||||
});
|
||||
|
||||
|
@ -173,14 +185,15 @@ fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item, trait_items
|
|||
|
||||
fn check_impl_items(cx: &LateContext<'_, '_>, item: &Item, impl_items: &[ImplItemRef]) {
|
||||
fn is_named_self(cx: &LateContext<'_, '_>, item: &ImplItemRef, name: &str) -> bool {
|
||||
item.ident.name == name && if let AssociatedItemKind::Method { has_self } = item.kind {
|
||||
has_self && {
|
||||
let did = cx.tcx.hir.local_def_id(item.id.node_id);
|
||||
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
|
||||
item.ident.name == name
|
||||
&& if let AssociatedItemKind::Method { has_self } = item.kind {
|
||||
has_self && {
|
||||
let did = cx.tcx.hir.local_def_id(item.id.node_id);
|
||||
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
let is_empty = if let Some(is_empty) = impl_items.iter().find(|i| is_named_self(cx, i, "is_empty")) {
|
||||
|
@ -251,7 +264,11 @@ fn check_len(
|
|||
span,
|
||||
&format!("length comparison to {}", if compare_to == 0 { "zero" } else { "one" }),
|
||||
"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,
|
||||
);
|
||||
}
|
||||
|
@ -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.
|
||||
fn has_is_empty_impl(cx: &LateContext<'_, '_>, id: DefId) -> bool {
|
||||
cx.tcx.inherent_impls(id).iter().any(|imp| {
|
||||
cx.tcx
|
||||
.associated_items(*imp)
|
||||
.any(|item| is_is_empty(cx, &item))
|
||||
})
|
||||
cx.tcx
|
||||
.inherent_impls(id)
|
||||
.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));
|
||||
match ty.sty {
|
||||
ty::Dynamic(ref tt, ..) => cx.tcx
|
||||
ty::Dynamic(ref tt, ..) => cx
|
||||
.tcx
|
||||
.associated_items(tt.principal().def_id())
|
||||
.any(|item| is_is_empty(cx, &item)),
|
||||
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
|
||||
// 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::{declare_tool_lint, lint_array};
|
||||
use if_chain::if_chain;
|
||||
use crate::rustc::hir;
|
||||
use crate::rustc::hir::BindingAnnotation;
|
||||
use crate::rustc::hir::def::Def;
|
||||
use crate::rustc_errors::Applicability;
|
||||
use crate::syntax::ast;
|
||||
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
|
||||
/// 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 {
|
||||
let mut v = UsedVisitor {
|
||||
cx,
|
||||
id,
|
||||
used: false,
|
||||
};
|
||||
let mut v = UsedVisitor { cx, id, used: false };
|
||||
hir::intravisit::walk_expr(&mut v, expr);
|
||||
v.used
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
// error-pattern:cargo-clippy
|
||||
|
||||
#![feature(box_syntax)]
|
||||
|
@ -18,7 +17,6 @@
|
|||
#![allow(clippy::missing_docs_in_private_items)]
|
||||
#![recursion_limit = "256"]
|
||||
#![feature(macro_at_most_once_rep)]
|
||||
|
||||
#![warn(rust_2018_idioms, trivial_casts, trivial_numeric_casts)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(try_from)]
|
||||
|
@ -216,12 +214,19 @@ mod reexport {
|
|||
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 redundant_field_names::RedundantFieldNames);
|
||||
store.register_pre_expansion_pass(Some(session), box non_expressive_names::NonExpressiveNames {
|
||||
single_char_binding_names_threshold: conf.single_char_binding_names_threshold,
|
||||
});
|
||||
store.register_pre_expansion_pass(
|
||||
Some(session),
|
||||
box non_expressive_names::NonExpressiveNames {
|
||||
single_char_binding_names_threshold: conf.single_char_binding_names_threshold,
|
||||
},
|
||||
);
|
||||
store.register_pre_expansion_pass(Some(session), box attrs::CfgAttrPass);
|
||||
}
|
||||
|
||||
|
@ -236,38 +241,49 @@ pub fn read_conf(reg: &rustc_plugin::Registry<'_>) -> Conf {
|
|||
match utils::conf::lookup_conf_file() {
|
||||
Ok(path) => path,
|
||||
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
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
let file_name = file_name.map(|file_name| if file_name.is_relative() {
|
||||
reg.sess
|
||||
.local_crate_source_file
|
||||
.as_ref()
|
||||
.and_then(|file| std::path::Path::new(&file).parent().map(std::path::Path::to_path_buf))
|
||||
.unwrap_or_default()
|
||||
.join(file_name)
|
||||
} else {
|
||||
file_name
|
||||
let file_name = file_name.map(|file_name| {
|
||||
if file_name.is_relative() {
|
||||
reg.sess
|
||||
.local_crate_source_file
|
||||
.as_ref()
|
||||
.and_then(|file| std::path::Path::new(&file).parent().map(std::path::Path::to_path_buf))
|
||||
.unwrap_or_default()
|
||||
.join(file_name)
|
||||
} else {
|
||||
file_name
|
||||
}
|
||||
});
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
},
|
||||
Err((err, span)) => {
|
||||
reg.sess.struct_span_err(span, err)
|
||||
.span_note(span, "Clippy will use default configuration")
|
||||
.emit();
|
||||
reg.sess
|
||||
.struct_span_err(span, err)
|
||||
.span_note(span, "Clippy will use default configuration")
|
||||
.emit();
|
||||
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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
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::*;
|
||||
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::syntax::source_map::Span;
|
||||
use crate::utils::{last_path_segment, span_lint};
|
||||
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
|
||||
/// relying on lifetime elision.
|
||||
|
@ -32,13 +31,15 @@ use crate::syntax::symbol::keywords;
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```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! {
|
||||
pub NEEDLESS_LIFETIMES,
|
||||
complexity,
|
||||
"using explicit lifetimes for references in function arguments when elision rules \
|
||||
would allow omitting them"
|
||||
pub NEEDLESS_LIFETIMES,
|
||||
complexity,
|
||||
"using explicit lifetimes for references in function arguments when elision rules \
|
||||
would allow omitting them"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for lifetimes in generics that are never used
|
||||
|
@ -52,7 +53,9 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// fn unused_lifetime<'a>(x: u8) { .. }
|
||||
/// fn unused_lifetime<'a>(x: u8) {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub EXTRA_UNUSED_LIFETIMES,
|
||||
|
@ -152,7 +155,8 @@ fn check_fn_inner<'a, 'tcx>(
|
|||
cx,
|
||||
NEEDLESS_LIFETIMES,
|
||||
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);
|
||||
|
@ -220,9 +224,7 @@ fn could_use_elision<'a, 'tcx: 'a>(
|
|||
// no output lifetimes, check distinctness of input lifetimes
|
||||
|
||||
// only unnamed and static, ok
|
||||
let unnamed_and_static = input_lts
|
||||
.iter()
|
||||
.all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
|
||||
let unnamed_and_static = input_lts.iter().all(|lt| *lt == RefLt::Unnamed || *lt == RefLt::Static);
|
||||
if unnamed_and_static {
|
||||
return false;
|
||||
}
|
||||
|
@ -320,7 +322,8 @@ impl<'v, 't> RefVisitor<'v, 't> {
|
|||
&& !last_path_segment.args.iter().any(|arg| match arg {
|
||||
GenericArg::Lifetime(_) => true,
|
||||
GenericArg::Type(_) => false,
|
||||
}) {
|
||||
})
|
||||
{
|
||||
let hir_id = self.cx.tcx.hir.node_to_hir_id(ty.id);
|
||||
match self.cx.tables.qpath_def(qpath, hir_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);
|
||||
},
|
||||
TyKind::Path(ref path) => {
|
||||
|
||||
self.collect_anonymous_lifetimes(path, ty);
|
||||
}
|
||||
},
|
||||
TyKind::Def(item, _) => {
|
||||
if let ItemKind::Existential(ref exist_ty) = self.cx.tcx.hir.expect_item(item.id).node {
|
||||
for bound in &exist_ty.bounds {
|
||||
|
@ -368,7 +370,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
|
|||
unreachable!()
|
||||
}
|
||||
walk_ty(self, ty);
|
||||
}
|
||||
},
|
||||
TyKind::TraitObject(ref bounds, ref lt) => {
|
||||
if !lt.is_elided() {
|
||||
self.abort = true;
|
||||
|
@ -410,9 +412,11 @@ fn has_where_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, where_clause: &
|
|||
// and check that all lifetimes are allowed
|
||||
match visitor.into_vec() {
|
||||
None => return false,
|
||||
Some(lts) => for lt in lts {
|
||||
if !allowed_lts.contains(<) {
|
||||
return true;
|
||||
Some(lts) => {
|
||||
for lt in lts {
|
||||
if !allowed_lts.contains(<) {
|
||||
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) {
|
||||
let hs = generics.params.iter()
|
||||
let hs = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|par| match par.kind {
|
||||
GenericParamKind::Lifetime { .. } => Some((par.name.ident().name, par.span)),
|
||||
_ => None,
|
||||
|
@ -468,7 +474,12 @@ fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx
|
|||
walk_fn_decl(&mut checker, func);
|
||||
|
||||
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[1].len());
|
||||
if !consistent {
|
||||
WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(),
|
||||
cx,
|
||||
lit.span);
|
||||
WarningType::InconsistentDigitGrouping.display(
|
||||
&digit_info.grouping_hint(),
|
||||
cx,
|
||||
lit.span,
|
||||
);
|
||||
}
|
||||
})
|
||||
.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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use itertools::Itertools;
|
||||
use crate::reexport::*;
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::hir::def::Def;
|
||||
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::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 if_chain::if_chain;
|
||||
use crate::rustc::middle::region;
|
||||
use itertools::Itertools;
|
||||
// use crate::rustc::middle::region::CodeExtent;
|
||||
use crate::consts::{constant, Constant};
|
||||
use crate::rustc::middle::expr_use_visitor::*;
|
||||
use crate::rustc::middle::mem_categorization::Categorization;
|
||||
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_errors::Applicability;
|
||||
use crate::rustc::ty::{self, Ty};
|
||||
use crate::rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use std::iter::{once, Iterator};
|
||||
use std::mem;
|
||||
use crate::rustc_errors::Applicability;
|
||||
use crate::syntax::ast;
|
||||
use crate::syntax::source_map::Span;
|
||||
use crate::syntax_pos::BytePos;
|
||||
use crate::utils::{in_macro, sugg, sext};
|
||||
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::{
|
||||
|
@ -92,11 +91,15 @@ declare_clippy_lint! {
|
|||
/// **Example:**
|
||||
/// ```rust
|
||||
/// // with `y` a `Vec` or slice:
|
||||
/// for x in y.iter() { .. }
|
||||
/// for x in y.iter() {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
/// can be rewritten to
|
||||
/// ```rust
|
||||
/// for x in &y { .. }
|
||||
/// for x in &y {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub EXPLICIT_ITER_LOOP,
|
||||
|
@ -114,11 +117,15 @@ declare_clippy_lint! {
|
|||
/// **Example:**
|
||||
/// ```rust
|
||||
/// // with `y` a `Vec` or slice:
|
||||
/// for x in y.into_iter() { .. }
|
||||
/// for x in y.into_iter() {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
/// can be rewritten to
|
||||
/// ```rust
|
||||
/// for x in y { .. }
|
||||
/// for x in y {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub EXPLICIT_INTO_ITER_LOOP,
|
||||
|
@ -139,7 +146,9 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// for x in y.next() { .. }
|
||||
/// for x in y.next() {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub ITER_NEXT_LOOP,
|
||||
|
@ -156,12 +165,16 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// for x in option { .. }
|
||||
/// for x in option {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This should be
|
||||
/// ```rust
|
||||
/// if let Some(x) = option { .. }
|
||||
/// if let Some(x) = option {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub FOR_LOOP_OVER_OPTION,
|
||||
|
@ -178,12 +191,16 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// for x in result { .. }
|
||||
/// for x in result {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This should be
|
||||
/// ```rust
|
||||
/// if let Ok(x) = result { .. }
|
||||
/// if let Ok(x) = result {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub FOR_LOOP_OVER_RESULT,
|
||||
|
@ -234,8 +251,7 @@ declare_clippy_lint! {
|
|||
declare_clippy_lint! {
|
||||
pub UNUSED_COLLECT,
|
||||
perf,
|
||||
"`collect()`ing an iterator without using the result; this is usually better \
|
||||
written as a for loop"
|
||||
"`collect()`ing an iterator without using the result; this is usually better written as a for loop"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for functions collecting an iterator when collect
|
||||
|
@ -273,7 +289,9 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// for x in 5..10-5 { .. } // oops, stray `-`
|
||||
/// for x in 5..10 - 5 {
|
||||
/// ..
|
||||
/// } // oops, stray `-`
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub REVERSE_RANGE_LOOP,
|
||||
|
@ -328,7 +346,9 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// while let Some(val) = iter() { .. }
|
||||
/// while let Some(val) = iter() {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub WHILE_LET_ON_ITERATOR,
|
||||
|
@ -346,13 +366,17 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// for (k, _) in &map { .. }
|
||||
/// for (k, _) in &map {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// could be replaced by
|
||||
///
|
||||
/// ```rust
|
||||
/// for k in map.keys() { .. }
|
||||
/// for k in map.keys() {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub FOR_KV_MAP,
|
||||
|
@ -370,7 +394,10 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// loop { ..; break; }
|
||||
/// loop {
|
||||
/// ..;
|
||||
/// break;
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub NEVER_LOOP,
|
||||
|
@ -412,7 +439,7 @@ declare_clippy_lint! {
|
|||
/// ```rust
|
||||
/// let i = 0;
|
||||
/// while i > 10 {
|
||||
/// println!("let me loop forever!");
|
||||
/// println!("let me loop forever!");
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
|
@ -459,8 +486,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
match expr.node {
|
||||
ExprKind::While(_, ref block, _) | ExprKind::Loop(ref block, _, _) => {
|
||||
match never_loop_block(block, expr.id) {
|
||||
NeverLoopResult::AlwaysBreak =>
|
||||
span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"),
|
||||
NeverLoopResult::AlwaysBreak => {
|
||||
span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops")
|
||||
},
|
||||
NeverLoopResult::MayContinueMainLoop | NeverLoopResult::Otherwise => (),
|
||||
}
|
||||
},
|
||||
|
@ -490,8 +518,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
// ensure "if let" compatible match structure
|
||||
match *source {
|
||||
MatchSource::Normal | MatchSource::IfLetDesugar { .. } => {
|
||||
if arms.len() == 2 && arms[0].pats.len() == 1 && arms[0].guard.is_none()
|
||||
&& arms[1].pats.len() == 1 && arms[1].guard.is_none()
|
||||
if arms.len() == 2
|
||||
&& 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)
|
||||
{
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
|
@ -533,12 +564,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
{
|
||||
let iter_expr = &method_args[0];
|
||||
let lhs_constructor = last_path_segment(qpath);
|
||||
if method_path.ident.name == "next" && match_trait_method(cx, match_expr, &paths::ITERATOR)
|
||||
&& lhs_constructor.ident.name == "Some" && (
|
||||
pat_args.is_empty()
|
||||
if method_path.ident.name == "next"
|
||||
&& match_trait_method(cx, match_expr, &paths::ITERATOR)
|
||||
&& lhs_constructor.ident.name == "Some"
|
||||
&& (pat_args.is_empty()
|
||||
|| !is_refutable(cx, &pat_args[0])
|
||||
&& !is_iterator_used_after_while_let(cx, iter_expr)
|
||||
&& !is_nested(cx, expr, &method_args[0]))
|
||||
&& !is_iterator_used_after_while_let(cx, iter_expr)
|
||||
&& !is_nested(cx, expr, &method_args[0]))
|
||||
{
|
||||
let iterator = snippet(cx, method_args[0].span, "_");
|
||||
let loop_var = if pat_args.is_empty() {
|
||||
|
@ -594,8 +626,7 @@ enum NeverLoopResult {
|
|||
|
||||
fn absorb_break(arg: &NeverLoopResult) -> NeverLoopResult {
|
||||
match *arg {
|
||||
NeverLoopResult::AlwaysBreak |
|
||||
NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
|
||||
NeverLoopResult::AlwaysBreak | NeverLoopResult::Otherwise => NeverLoopResult::Otherwise,
|
||||
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.
|
||||
fn combine_both(left: NeverLoopResult, right: NeverLoopResult) -> NeverLoopResult {
|
||||
match (left, right) {
|
||||
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) =>
|
||||
NeverLoopResult::MayContinueMainLoop,
|
||||
(NeverLoopResult::AlwaysBreak, _) | (_, NeverLoopResult::AlwaysBreak) =>
|
||||
NeverLoopResult::AlwaysBreak,
|
||||
(NeverLoopResult::Otherwise, NeverLoopResult::Otherwise) =>
|
||||
NeverLoopResult::Otherwise,
|
||||
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
|
||||
NeverLoopResult::MayContinueMainLoop
|
||||
},
|
||||
(NeverLoopResult::AlwaysBreak, _) | (_, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
|
||||
(NeverLoopResult::Otherwise, NeverLoopResult::Otherwise) => NeverLoopResult::Otherwise,
|
||||
}
|
||||
}
|
||||
|
||||
// Combine two results where only one of the part may have been executed.
|
||||
fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult {
|
||||
match (b1, b2) {
|
||||
(NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) =>
|
||||
NeverLoopResult::AlwaysBreak,
|
||||
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) =>
|
||||
NeverLoopResult::MayContinueMainLoop,
|
||||
(NeverLoopResult::Otherwise, _) | (_, NeverLoopResult::Otherwise) =>
|
||||
NeverLoopResult::Otherwise,
|
||||
(NeverLoopResult::AlwaysBreak, NeverLoopResult::AlwaysBreak) => NeverLoopResult::AlwaysBreak,
|
||||
(NeverLoopResult::MayContinueMainLoop, _) | (_, NeverLoopResult::MayContinueMainLoop) => {
|
||||
NeverLoopResult::MayContinueMainLoop
|
||||
},
|
||||
(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 {
|
||||
match expr.node {
|
||||
ExprKind::Box(ref e) |
|
||||
ExprKind::Unary(_, ref e) |
|
||||
ExprKind::Cast(ref e, _) |
|
||||
ExprKind::Type(ref e, _) |
|
||||
ExprKind::Field(ref e, _) |
|
||||
ExprKind::AddrOf(_, ref e) |
|
||||
ExprKind::Struct(_, _, Some(ref e)) |
|
||||
ExprKind::Repeat(ref e, _) => never_loop_expr(e, main_loop_id),
|
||||
ExprKind::Box(ref e)
|
||||
| ExprKind::Unary(_, ref e)
|
||||
| ExprKind::Cast(ref e, _)
|
||||
| ExprKind::Type(ref e, _)
|
||||
| ExprKind::Field(ref e, _)
|
||||
| ExprKind::AddrOf(_, ref e)
|
||||
| ExprKind::Struct(_, _, Some(ref e))
|
||||
| ExprKind::Repeat(ref e, _) => never_loop_expr(e, main_loop_id),
|
||||
ExprKind::Array(ref es) | ExprKind::MethodCall(_, _, ref es) | ExprKind::Tup(ref es) => {
|
||||
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::Binary(_, ref e1, ref e2) |
|
||||
ExprKind::Assign(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::Binary(_, ref e1, ref e2)
|
||||
| ExprKind::Assign(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::If(ref e, ref e2, ref e3) => {
|
||||
let e1 = never_loop_expr(e, 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))
|
||||
},
|
||||
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::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");
|
||||
if id == main_loop_id {
|
||||
NeverLoopResult::MayContinueMainLoop
|
||||
|
@ -706,9 +738,7 @@ fn never_loop_expr(expr: &Expr, main_loop_id: NodeId) -> NeverLoopResult {
|
|||
NeverLoopResult::AlwaysBreak
|
||||
}
|
||||
},
|
||||
ExprKind::Break(_, _) => {
|
||||
NeverLoopResult::AlwaysBreak
|
||||
},
|
||||
ExprKind::Break(_, _) => NeverLoopResult::AlwaysBreak,
|
||||
ExprKind::Ret(ref e) => {
|
||||
if let Some(ref e) = *e {
|
||||
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
|
||||
}
|
||||
},
|
||||
ExprKind::Struct(_, _, None) |
|
||||
ExprKind::Yield(_) |
|
||||
ExprKind::Closure(_, _, _, _, _) |
|
||||
ExprKind::InlineAsm(_, _, _) |
|
||||
ExprKind::Path(_) |
|
||||
ExprKind::Lit(_) => NeverLoopResult::Otherwise,
|
||||
ExprKind::Struct(_, _, None)
|
||||
| ExprKind::Yield(_)
|
||||
| ExprKind::Closure(_, _, _, _, _)
|
||||
| ExprKind::InlineAsm(_, _, _)
|
||||
| ExprKind::Path(_)
|
||||
| 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))
|
||||
.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))
|
||||
.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))
|
||||
.fold(NeverLoopResult::AlwaysBreak, combine_branches)
|
||||
}
|
||||
|
@ -779,10 +809,7 @@ struct Offset {
|
|||
|
||||
impl Offset {
|
||||
fn negative(s: String) -> Self {
|
||||
Self {
|
||||
value: s,
|
||||
negate: true,
|
||||
}
|
||||
Self { value: s, negate: true }
|
||||
}
|
||||
|
||||
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),
|
||||
_ => None,
|
||||
},
|
||||
ExprKind::Path(..) => if same_var(cx, idx, var) {
|
||||
Some(Offset::positive("0".into()))
|
||||
} else {
|
||||
None
|
||||
ExprKind::Path(..) => {
|
||||
if same_var(cx, idx, var) {
|
||||
Some(Offset::positive("0".into()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
|
||||
offset.map(|o| {
|
||||
FixedOffsetVar {
|
||||
var_name: snippet_opt(cx, seqexpr.span).unwrap_or_else(|| "???".into()),
|
||||
offset: o,
|
||||
}
|
||||
offset.map(|o| FixedOffsetVar {
|
||||
var_name: snippet_opt(cx, seqexpr.span).unwrap_or_else(|| "???".into()),
|
||||
offset: o,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
@ -890,7 +917,10 @@ fn get_indexed_assignments<'a, 'tcx>(
|
|||
var: ast::NodeId,
|
||||
) -> Option<(FixedOffsetVar, FixedOffsetVar)> {
|
||||
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)) => {
|
||||
// Source and destination must be different
|
||||
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 {
|
||||
let Block {
|
||||
ref stmts,
|
||||
ref expr,
|
||||
..
|
||||
ref stmts, ref expr, ..
|
||||
} = **b;
|
||||
|
||||
stmts
|
||||
|
@ -919,11 +947,7 @@ fn get_indexed_assignments<'a, 'tcx>(
|
|||
StmtKind::Decl(..) => None,
|
||||
StmtKind::Expr(ref e, _node_id) | StmtKind::Semi(ref e, _node_id) => Some(get_assignment(cx, e, var)),
|
||||
})
|
||||
.chain(
|
||||
expr.as_ref()
|
||||
.into_iter()
|
||||
.map(|e| Some(get_assignment(cx, &*e, var))),
|
||||
)
|
||||
.chain(expr.as_ref().into_iter().map(|e| Some(get_assignment(cx, &*e, var))))
|
||||
.filter_map(|op| op)
|
||||
.collect::<Option<Vec<_>>>()
|
||||
.unwrap_or_else(|| vec![])
|
||||
|
@ -973,33 +997,35 @@ fn detect_manual_memcpy<'a, 'tcx>(
|
|||
}
|
||||
};
|
||||
|
||||
let print_limit = |end: &Option<&Expr>, offset: Offset, var_name: &str| if let Some(end) = *end {
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(ref method, _, ref len_args) = end.node;
|
||||
if method.ident.name == "len";
|
||||
if len_args.len() == 1;
|
||||
if let Some(arg) = len_args.get(0);
|
||||
if snippet(cx, arg.span, "??") == var_name;
|
||||
then {
|
||||
return if offset.negate {
|
||||
format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let print_limit = |end: &Option<&Expr>, offset: Offset, var_name: &str| {
|
||||
if let Some(end) = *end {
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(ref method, _, ref len_args) = end.node;
|
||||
if method.ident.name == "len";
|
||||
if len_args.len() == 1;
|
||||
if let Some(arg) = len_args.get(0);
|
||||
if snippet(cx, arg.span, "??") == var_name;
|
||||
then {
|
||||
return if offset.negate {
|
||||
format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let end_str = match limits {
|
||||
ast::RangeLimits::Closed => {
|
||||
let end = sugg::Sugg::hir(cx, end, "<count>");
|
||||
format!("{}", end + sugg::ONE)
|
||||
},
|
||||
ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")),
|
||||
};
|
||||
|
||||
print_sum(&Offset::positive(end_str), &offset)
|
||||
} else {
|
||||
"..".into()
|
||||
}
|
||||
|
||||
let end_str = match limits {
|
||||
ast::RangeLimits::Closed => {
|
||||
let end = sugg::Sugg::hir(cx, end, "<count>");
|
||||
format!("{}", end + sugg::ONE)
|
||||
},
|
||||
ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")),
|
||||
};
|
||||
|
||||
print_sum(&Offset::positive(end_str), &offset)
|
||||
} else {
|
||||
"..".into()
|
||||
};
|
||||
|
||||
// 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!("{}.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 ");
|
||||
|
||||
|
@ -1166,7 +1195,10 @@ fn check_for_loop_range<'a, 'tcx>(
|
|||
"consider using an iterator".to_string(),
|
||||
vec![
|
||||
(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,
|
||||
NEEDLESS_RANGE_LOOP,
|
||||
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| {
|
||||
multispan_sugg(
|
||||
db,
|
||||
|
@ -1213,12 +1248,7 @@ fn is_len_call(expr: &Expr, var: Name) -> bool {
|
|||
false
|
||||
}
|
||||
|
||||
fn is_end_eq_array_len(
|
||||
cx: &LateContext<'_, '_>,
|
||||
end: &Expr,
|
||||
limits: ast::RangeLimits,
|
||||
indexed_ty: Ty<'_>,
|
||||
) -> bool {
|
||||
fn is_end_eq_array_len(cx: &LateContext<'_, '_>, end: &Expr, limits: ast::RangeLimits, indexed_ty: Ty<'_>) -> bool {
|
||||
if_chain! {
|
||||
if let ExprKind::Lit(ref lit) = end.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.
|
||||
let ty = cx.tables.expr_ty(start);
|
||||
let (sup, eq) = match (start_idx, end_idx) {
|
||||
(
|
||||
Constant::Int(start_idx),
|
||||
Constant::Int(end_idx),
|
||||
) => (match ty.sty {
|
||||
ty::Int(ity) => sext(cx.tcx, start_idx, ity) > sext(cx.tcx, end_idx, ity),
|
||||
ty::Uint(_) => start_idx > end_idx,
|
||||
_ => false,
|
||||
}, start_idx == end_idx),
|
||||
(Constant::Int(start_idx), Constant::Int(end_idx)) => (
|
||||
match ty.sty {
|
||||
ty::Int(ity) => sext(cx.tcx, start_idx, ity) > sext(cx.tcx, end_idx, ity),
|
||||
ty::Uint(_) => start_idx > end_idx,
|
||||
_ => false,
|
||||
},
|
||||
start_idx == end_idx,
|
||||
),
|
||||
_ => (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) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
|
||||
let muta = if method_name == "iter_mut" {
|
||||
"mut "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let muta = if method_name == "iter_mut" { "mut " } else { "" };
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
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
|
||||
// it's initialized to zero at the start of the loop.
|
||||
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));
|
||||
if let Some(parent_id) = parent_scope {
|
||||
if let Node::Block(block) = map.get(parent_id) {
|
||||
for (id, _) in visitor
|
||||
.states
|
||||
.iter()
|
||||
.filter(|&(_, v)| *v == VarState::IncrOnce)
|
||||
{
|
||||
for (id, _) in visitor.states.iter().filter(|&(_, v)| *v == VarState::IncrOnce) {
|
||||
let mut visitor2 = InitializeVisitor {
|
||||
cx,
|
||||
end_expr: expr,
|
||||
|
@ -1586,10 +1609,7 @@ fn check_for_mut_range_bound(cx: &LateContext<'_, '_>, arg: &Expr, body: &Expr)
|
|||
..
|
||||
}) = higher::range(cx, arg)
|
||||
{
|
||||
let mut_ids = vec![
|
||||
check_for_mutability(cx, start),
|
||||
check_for_mutability(cx, end),
|
||||
];
|
||||
let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
|
||||
if mut_ids[0].is_some() || mut_ids[1].is_some() {
|
||||
let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids);
|
||||
mut_warn_with_span(cx, span_low);
|
||||
|
@ -1631,7 +1651,11 @@ fn check_for_mutability(cx: &LateContext<'_, '_>, bound: &Expr) -> Option<NodeId
|
|||
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 {
|
||||
node_id_low: bound_ids[0],
|
||||
node_id_high: bound_ids[1],
|
||||
|
@ -1821,8 +1845,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
|
|||
}
|
||||
let old = self.prefer_mutable;
|
||||
match expr.node {
|
||||
ExprKind::AssignOp(_, ref lhs, ref rhs) |
|
||||
ExprKind::Assign(ref lhs, ref rhs) => {
|
||||
ExprKind::AssignOp(_, ref lhs, ref rhs) | ExprKind::Assign(ref lhs, ref rhs) => {
|
||||
self.prefer_mutable = true;
|
||||
self.visit_expr(lhs);
|
||||
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
|
||||
/// for `&T` and `&mut T`, such as `Vec`.
|
||||
#[rustfmt::skip]
|
||||
|
@ -1998,9 +2020,9 @@ enum VarState {
|
|||
|
||||
/// Scan a for loop for variables that are incremented exactly once.
|
||||
struct IncrementVisitor<'a, 'tcx: 'a> {
|
||||
cx: &'a LateContext<'a, 'tcx>, // context reference
|
||||
cx: &'a LateContext<'a, 'tcx>, // context reference
|
||||
states: FxHashMap<NodeId, VarState>, // incremented variables
|
||||
depth: u32, // depth of conditional expressions
|
||||
depth: u32, // depth of conditional expressions
|
||||
done: bool,
|
||||
}
|
||||
|
||||
|
@ -2244,8 +2266,10 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
|
|||
return;
|
||||
}
|
||||
match expr.node {
|
||||
ExprKind::Assign(ref path, _) | ExprKind::AssignOp(_, ref path, _) => if match_var(path, self.iterator) {
|
||||
self.nesting = RuledOut;
|
||||
ExprKind::Assign(ref path, _) | ExprKind::AssignOp(_, ref path, _) => {
|
||||
if match_var(path, self.iterator) {
|
||||
self.nesting = RuledOut;
|
||||
}
|
||||
},
|
||||
_ => 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) {
|
||||
used_in_condition.is_disjoint(&used_mutably)
|
||||
} else {
|
||||
return
|
||||
return;
|
||||
};
|
||||
let mutable_static_in_cond = var_visitor.def_ids.iter().any(|(_, v)| *v);
|
||||
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,
|
||||
WHILE_IMMUTABLE_CONDITION,
|
||||
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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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::source_map::Span;
|
||||
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;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -72,15 +73,26 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
let closure_expr = remove_blocks(&closure_body.value);
|
||||
then {
|
||||
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);
|
||||
},
|
||||
hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => match closure_expr.node {
|
||||
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]);
|
||||
hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => {
|
||||
match closure_expr.node {
|
||||
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]);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
@ -99,7 +111,10 @@ fn lint(cx: &LateContext<'_, '_>, replace: Span, root: Span, name: Ident, path:
|
|||
replace,
|
||||
"You are using an explicit closure for cloning elements",
|
||||
"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,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -7,16 +7,15 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir;
|
||||
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::{declare_tool_lint, lint_array};
|
||||
use crate::rustc_errors::Applicability;
|
||||
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::{in_macro, iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then};
|
||||
use if_chain::if_chain;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Pass;
|
||||
|
@ -87,7 +86,6 @@ declare_clippy_lint! {
|
|||
"using `result.map(f)`, where f is a function or closure that returns ()"
|
||||
}
|
||||
|
||||
|
||||
impl LintPass for Pass {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
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 {
|
||||
hir::ExprKind::Call(_, _) |
|
||||
hir::ExprKind::MethodCall(_, _, _) => {
|
||||
hir::ExprKind::Call(_, _) | hir::ExprKind::MethodCall(_, _, _) => {
|
||||
// Calls can't be reduced any more
|
||||
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.
|
||||
None
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
|
@ -189,15 +186,14 @@ fn let_binding_name(cx: &LateContext<'_, '_>, var_arg: &hir::Expr) -> String {
|
|||
match &var_arg.node {
|
||||
hir::ExprKind::Field(_, _) => snippet(cx, var_arg.span, "_").replace(".", "_"),
|
||||
hir::ExprKind::Path(_) => format!("_{}", snippet(cx, var_arg.span, "")),
|
||||
_ => "_".to_string()
|
||||
_ => "_".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn suggestion_msg(function_type: &str, map_type: &str) -> String {
|
||||
format!(
|
||||
"called `map(f)` on an {0} value where `f` is a unit {1}",
|
||||
map_type,
|
||||
function_type
|
||||
map_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 fn_arg = &map_args[1];
|
||||
|
||||
let (map_type, variant, lint) =
|
||||
if match_type(cx, cx.tables.expr_ty(var_arg), &paths::OPTION) {
|
||||
("Option", "Some", OPTION_MAP_UNIT_FN)
|
||||
} else if match_type(cx, cx.tables.expr_ty(var_arg), &paths::RESULT) {
|
||||
("Result", "Ok", RESULT_MAP_UNIT_FN)
|
||||
} else {
|
||||
return
|
||||
};
|
||||
let (map_type, variant, lint) = if match_type(cx, cx.tables.expr_ty(var_arg), &paths::OPTION) {
|
||||
("Option", "Some", OPTION_MAP_UNIT_FN)
|
||||
} else if match_type(cx, cx.tables.expr_ty(var_arg), &paths::RESULT) {
|
||||
("Result", "Ok", RESULT_MAP_UNIT_FN)
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
if is_unit_function(cx, fn_arg) {
|
||||
let msg = suggestion_msg("function", map_type);
|
||||
let suggestion = format!("if let {0}({1}) = {2} {{ {3}(...) }}",
|
||||
variant,
|
||||
let_binding_name(cx, var_arg),
|
||||
snippet(cx, var_arg.span, "_"),
|
||||
snippet(cx, fn_arg.span, "_"));
|
||||
let suggestion = format!(
|
||||
"if let {0}({1}) = {2} {{ {3}(...) }}",
|
||||
variant,
|
||||
let_binding_name(cx, var_arg),
|
||||
snippet(cx, var_arg.span, "_"),
|
||||
snippet(cx, fn_arg.span, "_")
|
||||
);
|
||||
|
||||
span_lint_and_then(cx, lint, expr.span, &msg, |db| {
|
||||
db.span_suggestion_with_applicability(stmt.span,
|
||||
"try this",
|
||||
suggestion,
|
||||
Applicability::Unspecified);
|
||||
db.span_suggestion_with_applicability(stmt.span, "try this", suggestion, Applicability::Unspecified);
|
||||
});
|
||||
} else if let Some((binding, closure_expr)) = unit_closure(cx, fn_arg) {
|
||||
let msg = suggestion_msg("closure", map_type);
|
||||
|
||||
span_lint_and_then(cx, lint, expr.span, &msg, |db| {
|
||||
if let Some(reduced_expr_span) = reduce_unit_expression(cx, closure_expr) {
|
||||
let suggestion = format!("if let {0}({1}) = {2} {{ {3} }}",
|
||||
variant,
|
||||
snippet(cx, binding.pat.span, "_"),
|
||||
snippet(cx, var_arg.span, "_"),
|
||||
snippet(cx, reduced_expr_span, "_"));
|
||||
let suggestion = format!(
|
||||
"if let {0}({1}) = {2} {{ {3} }}",
|
||||
variant,
|
||||
snippet(cx, binding.pat.span, "_"),
|
||||
snippet(cx, var_arg.span, "_"),
|
||||
snippet(cx, reduced_expr_span, "_")
|
||||
);
|
||||
db.span_suggestion_with_applicability(
|
||||
stmt.span,
|
||||
"try this",
|
||||
|
@ -245,16 +241,13 @@ fn lint_map_unit_fn(cx: &LateContext<'_, '_>, stmt: &hir::Stmt, expr: &hir::Expr
|
|||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
} else {
|
||||
let suggestion = format!("if let {0}({1}) = {2} {{ ... }}",
|
||||
variant,
|
||||
snippet(cx, binding.pat.span, "_"),
|
||||
snippet(cx, var_arg.span, "_"));
|
||||
db.span_suggestion_with_applicability(
|
||||
stmt.span,
|
||||
"try this",
|
||||
suggestion,
|
||||
Applicability::Unspecified,
|
||||
let suggestion = format!(
|
||||
"if let {0}({1}) = {2} {{ ... }}",
|
||||
variant,
|
||||
snippet(cx, binding.pat.span, "_"),
|
||||
snippet(cx, var_arg.span, "_")
|
||||
);
|
||||
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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::consts::{constant, Constant};
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use if_chain::if_chain;
|
||||
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
|
||||
use crate::rustc::ty::{self, Ty};
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::Bound;
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::rustc_errors::Applicability;
|
||||
use crate::syntax::ast::LitKind;
|
||||
use crate::syntax::source_map::Span;
|
||||
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::consts::{constant, Constant};
|
||||
use crate::rustc_errors::Applicability;
|
||||
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 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`
|
||||
/// will usually suffice.
|
||||
|
@ -36,14 +36,13 @@ use crate::rustc_errors::Applicability;
|
|||
/// ```rust
|
||||
/// match x {
|
||||
/// Some(ref foo) => bar(foo),
|
||||
/// _ => ()
|
||||
/// _ => (),
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub SINGLE_MATCH,
|
||||
style,
|
||||
"a match statement with a single nontrivial arm (i.e. where the other arm \
|
||||
is `_ => {}`) instead of `if let`"
|
||||
"a match statement with a single nontrivial arm (i.e. where the other arm is `_ => {}`) instead of `if let`"
|
||||
}
|
||||
|
||||
/// **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! {
|
||||
pub SINGLE_MATCH_ELSE,
|
||||
pedantic,
|
||||
"a match statement with a two arms where the second arm's pattern is a wildcard \
|
||||
instead of `if let`"
|
||||
"a match statement with a two arms where the second arm's pattern is a wildcard instead of `if let`"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for matches where all arms match a reference,
|
||||
|
@ -131,8 +129,8 @@ declare_clippy_lint! {
|
|||
/// ```rust
|
||||
/// let x = 5;
|
||||
/// match x {
|
||||
/// 1 ... 10 => println!("1 ... 10"),
|
||||
/// 5 ... 15 => println!("5 ... 15"),
|
||||
/// 1...10 => println!("1 ... 10"),
|
||||
/// 5...15 => println!("5 ... 15"),
|
||||
/// _ => (),
|
||||
/// }
|
||||
/// ```
|
||||
|
@ -152,7 +150,7 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// let x : Result(i32, &str) = Ok(3);
|
||||
/// let x: Result(i32, &str) = Ok(3);
|
||||
/// match x {
|
||||
/// Ok(_) => println!("ok"),
|
||||
/// Err(_) => panic!("err"),
|
||||
|
@ -175,8 +173,8 @@ declare_clippy_lint! {
|
|||
/// ```rust
|
||||
/// let x: Option<()> = None;
|
||||
/// let r: Option<&()> = match x {
|
||||
/// None => None,
|
||||
/// Some(ref v) => Some(v),
|
||||
/// None => None,
|
||||
/// Some(ref v) => Some(v),
|
||||
/// };
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
|
@ -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]) {
|
||||
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>) {
|
||||
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, "..")));
|
||||
fn report_single_match_single_pattern(
|
||||
cx: &LateContext<'_, '_>,
|
||||
ex: &Expr,
|
||||
arms: &[Arm],
|
||||
expr: &Expr,
|
||||
els: Option<&Expr>,
|
||||
) {
|
||||
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(
|
||||
cx,
|
||||
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
|
||||
let candidates = &[
|
||||
(&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) {
|
||||
if arms.len() == 2 &&
|
||||
arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
|
||||
arms[1].pats.len() == 1 && arms[1].guard.is_none() {
|
||||
if arms.len() == 2
|
||||
&& arms[0].pats.len() == 1
|
||||
&& 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]) {
|
||||
is_ref_some_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
|
||||
};
|
||||
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;
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
@ -485,7 +507,11 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: &
|
|||
expr.span,
|
||||
&format!("use {}() instead", suggestion),
|
||||
"try this",
|
||||
format!("{}.{}()", snippet_with_applicability(cx, ex.span, "_", &mut applicability), suggestion),
|
||||
format!(
|
||||
"{}.{}()",
|
||||
snippet_with_applicability(cx, ex.span, "_", &mut applicability),
|
||||
suggestion
|
||||
),
|
||||
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.
|
||||
fn all_ranges<'a, 'tcx>(
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
arms: &'tcx [Arm],
|
||||
) -> Vec<SpannedRange<Constant>> {
|
||||
fn all_ranges<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arms: &'tcx [Arm]) -> Vec<SpannedRange<Constant>> {
|
||||
arms.iter()
|
||||
.flat_map(|arm| {
|
||||
if let Arm {
|
||||
ref pats,
|
||||
guard: None,
|
||||
..
|
||||
ref pats, guard: None, ..
|
||||
} = *arm
|
||||
{
|
||||
pats.iter()
|
||||
} else {
|
||||
[].iter()
|
||||
}.filter_map(|pat| {
|
||||
}
|
||||
.filter_map(|pat| {
|
||||
if let PatKind::Range(ref lhs, ref rhs, ref range_end) = pat.node {
|
||||
let lhs = constant(cx, cx.tables, lhs)?.0;
|
||||
let rhs = constant(cx, cx.tables, rhs)?.0;
|
||||
|
@ -516,12 +538,18 @@ fn all_ranges<'a, 'tcx>(
|
|||
RangeEnd::Included => Bound::Included(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 {
|
||||
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
|
||||
|
@ -545,24 +573,15 @@ fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
|
|||
ranges
|
||||
.iter()
|
||||
.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,
|
||||
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,
|
||||
node: (start, Bound::Excluded(end)),
|
||||
}),
|
||||
(
|
||||
Constant::Int(start),
|
||||
Bound::Unbounded,
|
||||
) => Some(SpannedRange {
|
||||
(Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
|
||||
span: range.span,
|
||||
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 {
|
||||
let mapped = arms.iter()
|
||||
let mapped = arms
|
||||
.iter()
|
||||
.flat_map(|a| &a.pats)
|
||||
.map(|p| {
|
||||
match p.node {
|
||||
|
@ -682,8 +702,10 @@ where
|
|||
|
||||
for (a, b) in values.iter().zip(values.iter().skip(1)) {
|
||||
match (a, b) {
|
||||
(&Kind::Start(_, ra), &Kind::End(_, rb)) => if ra.node != rb.node {
|
||||
return Some((ra, rb));
|
||||
(&Kind::Start(_, ra), &Kind::End(_, rb)) => {
|
||||
if ra.node != rb.node {
|
||||
return Some((ra, rb));
|
||||
}
|
||||
},
|
||||
(&Kind::End(a, _), &Kind::Start(b, _)) if a != Bound::Included(b) => (),
|
||||
_ => return Some((a.range(), b.range())),
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::{Expr, ExprKind};
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
|
|
|
@ -7,10 +7,9 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::{Expr, ExprKind};
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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};
|
||||
|
||||
/// **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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::{Expr, ExprKind, MutMutable, QPath};
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
|
|
|
@ -7,11 +7,10 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir;
|
||||
use crate::rustc::hir::def::Def;
|
||||
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_errors::Applicability;
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
|
@ -95,7 +94,9 @@ declare_clippy_lint! {
|
|||
/// ```rust
|
||||
/// struct X;
|
||||
/// impl X {
|
||||
/// fn add(&self, other: &X) -> X { .. }
|
||||
/// fn add(&self, other: &X) -> X {
|
||||
/// ..
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
|
@ -124,14 +125,15 @@ declare_clippy_lint! {
|
|||
/// **Example:**
|
||||
/// ```rust
|
||||
/// impl X {
|
||||
/// fn as_str(self) -> &str { .. }
|
||||
/// fn as_str(self) -> &str {
|
||||
/// ..
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub WRONG_SELF_CONVENTION,
|
||||
style,
|
||||
"defining a method named with an established prefix (like \"into_\") that takes \
|
||||
`self` with the wrong convention"
|
||||
"defining a method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
|
||||
}
|
||||
|
||||
/// **What it does:** This is the same as
|
||||
|
@ -146,14 +148,15 @@ declare_clippy_lint! {
|
|||
/// **Example:**
|
||||
/// ```rust
|
||||
/// impl X {
|
||||
/// pub fn as_str(self) -> &str { .. }
|
||||
/// pub fn as_str(self) -> &str {
|
||||
/// ..
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub WRONG_PUB_SELF_CONVENTION,
|
||||
restriction,
|
||||
"defining a public method named with an established prefix (like \"into_\") that takes \
|
||||
`self` with the wrong convention"
|
||||
"defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for usage of `ok().expect(..)`.
|
||||
|
@ -170,8 +173,7 @@ declare_clippy_lint! {
|
|||
declare_clippy_lint! {
|
||||
pub OK_EXPECT,
|
||||
style,
|
||||
"using `ok().expect()`, which gives worse error messages than \
|
||||
calling `expect` directly on the Result"
|
||||
"using `ok().expect()`, which gives worse error messages than calling `expect` directly on the Result"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for usage of `_.map(_).unwrap_or(_)`.
|
||||
|
@ -186,10 +188,10 @@ declare_clippy_lint! {
|
|||
/// x.map(|a| a + 1).unwrap_or(0)
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub OPTION_MAP_UNWRAP_OR,
|
||||
pedantic,
|
||||
"using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \
|
||||
`map_or(a, f)`"
|
||||
pub OPTION_MAP_UNWRAP_OR,
|
||||
pedantic,
|
||||
"using `Option.map(f).unwrap_or(a)`, which is more succinctly expressed as \
|
||||
`map_or(a, f)`"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for usage of `_.map(_).unwrap_or_else(_)`.
|
||||
|
@ -206,8 +208,7 @@ declare_clippy_lint! {
|
|||
declare_clippy_lint! {
|
||||
pub OPTION_MAP_UNWRAP_OR_ELSE,
|
||||
pedantic,
|
||||
"using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \
|
||||
`map_or_else(g, f)`"
|
||||
"using `Option.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `map_or_else(g, f)`"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for usage of `result.map(_).unwrap_or_else(_)`.
|
||||
|
@ -224,8 +225,7 @@ declare_clippy_lint! {
|
|||
declare_clippy_lint! {
|
||||
pub RESULT_MAP_UNWRAP_OR_ELSE,
|
||||
pedantic,
|
||||
"using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as \
|
||||
`.ok().map_or_else(g, f)`"
|
||||
"using `Result.map(f).unwrap_or_else(g)`, which is more succinctly expressed as `.ok().map_or_else(g, f)`"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for usage of `_.map_or(None, _)`.
|
||||
|
@ -242,8 +242,7 @@ declare_clippy_lint! {
|
|||
declare_clippy_lint! {
|
||||
pub OPTION_MAP_OR_NONE,
|
||||
style,
|
||||
"using `Option.map_or(None, f)`, which is more succinctly expressed as \
|
||||
`and_then(f)`"
|
||||
"using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for usage of `_.filter(_).next()`.
|
||||
|
@ -277,8 +276,7 @@ declare_clippy_lint! {
|
|||
declare_clippy_lint! {
|
||||
pub MAP_FLATTEN,
|
||||
pedantic,
|
||||
"using combinations of `flatten` and `map` which can usually be written as a \
|
||||
single method call"
|
||||
"using combinations of `flatten` and `map` which can usually be written as a single method call"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for usage of `_.filter(_).map(_)`,
|
||||
|
@ -297,8 +295,7 @@ declare_clippy_lint! {
|
|||
declare_clippy_lint! {
|
||||
pub FILTER_MAP,
|
||||
pedantic,
|
||||
"using combinations of `filter`, `map`, `filter_map` and `flat_map` which can \
|
||||
usually be written as a single method call"
|
||||
"using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for an iterator search (such as `find()`,
|
||||
|
@ -316,8 +313,7 @@ declare_clippy_lint! {
|
|||
declare_clippy_lint! {
|
||||
pub SEARCH_IS_SOME,
|
||||
complexity,
|
||||
"using an iterator search followed by `is_some()`, which is more succinctly \
|
||||
expressed as a call to `any()`"
|
||||
"using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for usage of `.chars().next()` on a `str` to check
|
||||
|
@ -437,10 +433,10 @@ declare_clippy_lint! {
|
|||
/// **Example:**
|
||||
/// ```rust
|
||||
/// fn main() {
|
||||
/// let x = vec![1];
|
||||
/// let y = &&x;
|
||||
/// let z = y.clone();
|
||||
/// println!("{:p} {:p}",*y, z); // prints out the same pointer
|
||||
/// let x = vec![1];
|
||||
/// let y = &&x;
|
||||
/// let z = y.clone();
|
||||
/// println!("{:p} {:p}", *y, z); // prints out the same pointer
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
|
@ -482,8 +478,7 @@ declare_clippy_lint! {
|
|||
declare_clippy_lint! {
|
||||
pub SINGLE_CHAR_PATTERN,
|
||||
perf,
|
||||
"using a single-character str where a char could be used, e.g. \
|
||||
`_.split(\"x\")`"
|
||||
"using a single-character str where a char could be used, e.g. `_.split(\"x\")`"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for getting the inner pointer of a temporary
|
||||
|
@ -635,13 +630,13 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// let s = [1,2,3,4,5];
|
||||
/// let s2 : Vec<isize> = s[..].iter().cloned().collect();
|
||||
/// let s = [1, 2, 3, 4, 5];
|
||||
/// let s2: Vec<isize> = s[..].iter().cloned().collect();
|
||||
/// ```
|
||||
/// The better use would be:
|
||||
/// ```rust
|
||||
/// let s = [1,2,3,4,5];
|
||||
/// let s2 : Vec<isize> = s.to_vec();
|
||||
/// let s = [1, 2, 3, 4, 5];
|
||||
/// let s2: Vec<isize> = s.to_vec();
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub ITER_CLONED_COLLECT,
|
||||
|
@ -676,12 +671,12 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// let x: &[i32] = &[1,2,3,4,5];
|
||||
/// let x: &[i32] = &[1, 2, 3, 4, 5];
|
||||
/// do_stuff(x.as_ref());
|
||||
/// ```
|
||||
/// The correct use would be:
|
||||
/// ```rust
|
||||
/// let x: &[i32] = &[1,2,3,4,5];
|
||||
/// let x: &[i32] = &[1, 2, 3, 4, 5];
|
||||
/// do_stuff(x);
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
|
@ -690,7 +685,6 @@ declare_clippy_lint! {
|
|||
"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.
|
||||
/// Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
|
||||
/// `sum` or `product`.
|
||||
|
@ -714,7 +708,6 @@ declare_clippy_lint! {
|
|||
"using `fold` when a more succinct alternative exists"
|
||||
}
|
||||
|
||||
|
||||
/// **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
|
||||
/// 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]),
|
||||
["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0]),
|
||||
["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]),
|
||||
_ => {}
|
||||
_ => {},
|
||||
}
|
||||
|
||||
match expr.node {
|
||||
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_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args);
|
||||
|
||||
|
@ -886,9 +878,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
}
|
||||
|
||||
match self_ty.sty {
|
||||
ty::Ref(_, ty, _) if ty.sty == ty::Str => for &(method, pos) in &PATTERN_METHODS {
|
||||
if method_call.ident.name == method && args.len() > pos {
|
||||
lint_single_char_pattern(cx, expr, &args[pos]);
|
||||
ty::Ref(_, ty, _) if ty.sty == ty::Str => {
|
||||
for &(method, pos) in &PATTERN_METHODS {
|
||||
if method_call.ident.name == method && args.len() > pos {
|
||||
lint_single_char_pattern(cx, expr, &args[pos]);
|
||||
}
|
||||
}
|
||||
},
|
||||
ty::Ref(..) if method_call.ident.name == "into_iter" => {
|
||||
|
@ -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 {
|
||||
expr,
|
||||
chain: lhs,
|
||||
|
@ -905,7 +901,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
eq: op.node == hir::BinOpKind::Eq,
|
||||
};
|
||||
lint_binary_expr_with_method_call(cx, &mut info);
|
||||
},
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
@ -963,7 +959,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
.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;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
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 let TyKind::Opaque(def_id, _) = ret_ty.sty {
|
||||
|
||||
// one of the associated types must be Self
|
||||
for predicate in &cx.tcx.predicates_of(def_id).predicates {
|
||||
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);
|
||||
|
||||
// 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) {
|
||||
span_lint(cx,
|
||||
NEW_RET_NO_SELF,
|
||||
implitem.span,
|
||||
"methods called `new` usually return `Self`");
|
||||
span_lint(
|
||||
cx,
|
||||
NEW_RET_NO_SELF,
|
||||
implitem.span,
|
||||
"methods called `new` usually return `Self`",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1043,7 +1045,10 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa
|
|||
span,
|
||||
&format!("use of `{}` followed by a call to `{}`", name, path),
|
||||
"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,
|
||||
);
|
||||
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) => {
|
||||
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) {
|
||||
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) => {
|
||||
check_general_case(cx, name, method_span, span, &args[0], &args[1], !or_args.is_empty(), expr.span)
|
||||
},
|
||||
hir::ExprKind::MethodCall(_, span, ref or_args) => check_general_case(
|
||||
cx,
|
||||
name,
|
||||
method_span,
|
||||
span,
|
||||
&args[0],
|
||||
&args[1],
|
||||
!or_args.is_empty(),
|
||||
expr.span,
|
||||
),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
@ -1137,12 +1158,13 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa
|
|||
/// Checks for the `EXPECT_FUN_CALL` lint.
|
||||
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>> {
|
||||
let arg = match &arg.node {
|
||||
hir::ExprKind::AddrOf(_, expr)=> expr,
|
||||
let arg = match &arg.node {
|
||||
hir::ExprKind::AddrOf(_, expr) => expr,
|
||||
hir::ExprKind::MethodCall(method_name, _, args)
|
||||
if method_name.ident.name == "as_str" ||
|
||||
method_name.ident.name == "as_ref"
|
||||
=> &args[0],
|
||||
if method_name.ident.name == "as_str" || method_name.ident.name == "as_ref" =>
|
||||
{
|
||||
&args[0]
|
||||
},
|
||||
_ => 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::Match(ref format_arg_expr, _, _) = format_arg.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;
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
if let Some(format_args) = extract_format_args(arg) {
|
||||
|
@ -1272,28 +1299,30 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr, arg: &hir::Exp
|
|||
expr.span,
|
||||
"using `clone` on a double-reference; \
|
||||
this will copy the reference instead of cloning the inner type",
|
||||
|db| if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
|
||||
let mut ty = innermost;
|
||||
let mut n = 0;
|
||||
while let ty::Ref(_, inner, _) = ty.sty {
|
||||
ty = inner;
|
||||
n += 1;
|
||||
|db| {
|
||||
if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) {
|
||||
let mut ty = innermost;
|
||||
let mut n = 0;
|
||||
while let ty::Ref(_, inner, _) = ty.sty {
|
||||
ty = inner;
|
||||
n += 1;
|
||||
}
|
||||
let refs: String = iter::repeat('&').take(n + 1).collect();
|
||||
let derefs: String = iter::repeat('*').take(n).collect();
|
||||
let explicit = format!("{}{}::clone({})", refs, ty, snip);
|
||||
db.span_suggestion_with_applicability(
|
||||
expr.span,
|
||||
"try dereferencing it",
|
||||
format!("{}({}{}).clone()", refs, derefs, snip.deref()),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
db.span_suggestion_with_applicability(
|
||||
expr.span,
|
||||
"or try being explicit about what type to clone",
|
||||
explicit,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
let refs: String = iter::repeat('&').take(n + 1).collect();
|
||||
let derefs: String = iter::repeat('*').take(n).collect();
|
||||
let explicit = format!("{}{}::clone({})", refs, ty, snip);
|
||||
db.span_suggestion_with_applicability(
|
||||
expr.span,
|
||||
"try dereferencing it",
|
||||
format!("{}({}{}).clone()", refs, derefs, snip.deref()),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
db.span_suggestion_with_applicability(
|
||||
expr.span,
|
||||
"or try being explicit about what type to clone",
|
||||
explicit,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
},
|
||||
);
|
||||
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
|
||||
hir::ExprKind::MethodCall(..) => return,
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
hir::Node::Stmt(stmt) => {
|
||||
if let hir::StmtKind::Decl(ref decl, _) = stmt.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| {
|
||||
if let Some((text, snip)) = snip {
|
||||
db.span_suggestion_with_applicability(
|
||||
expr.span,
|
||||
text,
|
||||
snip,
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
db.span_suggestion_with_applicability(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,
|
||||
"using '.clone()' on a ref-counted pointer",
|
||||
"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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn lint_string_extend(cx: &LateContext<'_, '_>, expr: &hir::Expr, args: &[hir::Expr]) {
|
||||
let arg = &args[1];
|
||||
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],
|
||||
op: hir::BinOpKind,
|
||||
replacement_method_name: &str,
|
||||
replacement_has_args: bool) {
|
||||
|
||||
replacement_has_args: bool,
|
||||
) {
|
||||
if_chain! {
|
||||
// Extract the body of the closure passed to fold
|
||||
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;
|
||||
}
|
||||
|
||||
assert!(fold_args.len() == 3,
|
||||
"Expected fold_args to have three entries - the receiver, the initial value and the closure");
|
||||
assert!(
|
||||
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
|
||||
match fold_args[1].node {
|
||||
hir::ExprKind::Lit(ref lit) => {
|
||||
match lit.node {
|
||||
ast::LitKind::Bool(false) => check_fold_with_op(
|
||||
cx, fold_args, hir::BinOpKind::Or, "any", true
|
||||
),
|
||||
ast::LitKind::Bool(true) => check_fold_with_op(
|
||||
cx, fold_args, hir::BinOpKind::And, "all", 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
|
||||
),
|
||||
_ => return
|
||||
}
|
||||
}
|
||||
_ => return
|
||||
hir::ExprKind::Lit(ref lit) => match lit.node {
|
||||
ast::LitKind::Bool(false) => check_fold_with_op(cx, fold_args, hir::BinOpKind::Or, "any", true),
|
||||
ast::LitKind::Bool(true) => check_fold_with_op(cx, fold_args, hir::BinOpKind::And, "all", 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),
|
||||
_ => return,
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1553,8 +1573,7 @@ fn lint_iter_nth(cx: &LateContext<'_, '_>, expr: &hir::Expr, iter_args: &[hir::E
|
|||
expr.span,
|
||||
&format!(
|
||||
"called `.iter{0}().nth()` on a {1}. Calling `.get{0}()` is both faster and more readable",
|
||||
mut_str,
|
||||
caller_type
|
||||
mut_str, 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 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(
|
||||
cx,
|
||||
GET_UNWRAP,
|
||||
expr.span,
|
||||
&format!(
|
||||
"called `.get{0}().unwrap()` on a {1}. Using `[]` is more clear and more concise",
|
||||
mut_str,
|
||||
caller_type
|
||||
mut_str, caller_type
|
||||
),
|
||||
"try this",
|
||||
format!(
|
||||
|
@ -1645,10 +1669,12 @@ fn derefs_to_slice(cx: &LateContext<'_, '_>, expr: &hir::Expr, ty: Ty<'_>) -> Op
|
|||
match ty.sty {
|
||||
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::Ref(_, inner, _) => if may_slice(cx, inner) {
|
||||
sugg::Sugg::hir_opt(cx, expr)
|
||||
} else {
|
||||
None
|
||||
ty::Ref(_, inner, _) => {
|
||||
if may_slice(cx, inner) {
|
||||
sugg::Sugg::hir_opt(cx, expr)
|
||||
} else {
|
||||
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 \
|
||||
using expect() to provide a better panic \
|
||||
message",
|
||||
kind,
|
||||
none_value
|
||||
kind, none_value
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -1711,11 +1736,7 @@ fn lint_map_unwrap_or(cx: &LateContext<'_, '_>, expr: &hir::Expr, map_args: &[hi
|
|||
// lint message
|
||||
// comparing the snippet from source to raw text ("None") below is safe
|
||||
// because we already have checked the type.
|
||||
let arg = if unwrap_snippet == "None" {
|
||||
"None"
|
||||
} else {
|
||||
"a"
|
||||
};
|
||||
let arg = if unwrap_snippet == "None" { "None" } else { "a" };
|
||||
let suggest = if unwrap_snippet == "None" {
|
||||
"and_then(f)"
|
||||
} else {
|
||||
|
@ -1724,8 +1745,7 @@ fn lint_map_unwrap_or(cx: &LateContext<'_, '_>, expr: &hir::Expr, map_args: &[hi
|
|||
let msg = &format!(
|
||||
"called `map(f).unwrap_or({})` on an Option value. \
|
||||
This can be done more directly by calling `{}` instead",
|
||||
arg,
|
||||
suggest
|
||||
arg, suggest
|
||||
);
|
||||
// lint, with note if neither arg is > 1 line and both map() and
|
||||
// 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!(
|
||||
"replace `map({}).unwrap_or({})` with `{}`",
|
||||
map_snippet,
|
||||
unwrap_snippet,
|
||||
suggest
|
||||
map_snippet, unwrap_snippet, suggest
|
||||
);
|
||||
span_note_and_lint(cx, OPTION_MAP_UNWRAP_OR, expr.span, msg, expr.span, ¬e);
|
||||
} 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`
|
||||
fn lint_map_flatten<'a, 'tcx>(
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
map_args: &'tcx [hir::Expr],
|
||||
) {
|
||||
fn lint_map_flatten<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr, map_args: &'tcx [hir::Expr]) {
|
||||
// lint if caller of `.map().flatten()` is an Iterator
|
||||
if match_trait_method(cx, expr, &paths::ITERATOR) {
|
||||
let msg = "called `map(..).flatten()` on an `Iterator`. \
|
||||
|
@ -1971,7 +1985,10 @@ fn lint_search_is_some<'a, 'tcx>(
|
|||
expr.span,
|
||||
&msg,
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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`
|
||||
// exists and has the desired signature. Unfortunately FnCtxt is not exported
|
||||
// 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 {
|
||||
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
|
||||
|
@ -2218,8 +2238,7 @@ fn lint_into_iter(cx: &LateContext<'_, '_>, expr: &hir::Expr, self_ref_ty: ty::T
|
|||
method_span,
|
||||
&format!(
|
||||
"this .into_iter() call is equivalent to .{}() and will not move the {}",
|
||||
method_name,
|
||||
kind,
|
||||
method_name, kind,
|
||||
),
|
||||
"call directly",
|
||||
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`).
|
||||
fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option<Ty<'a>> {
|
||||
if let ty::Adt(_, substs) = ty.sty {
|
||||
|
@ -2321,7 +2339,6 @@ const PATTERN_METHODS: [(&str, usize); 17] = [
|
|||
("trim_right_matches", 1),
|
||||
];
|
||||
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
enum SelfKind {
|
||||
Value,
|
||||
|
@ -2397,31 +2414,36 @@ 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| {
|
||||
generics.params.iter().any(|param| match param.kind {
|
||||
hir::GenericParamKind::Type { .. } => {
|
||||
param.name.ident().name == seg.ident.name && param.bounds.iter().any(|bound| {
|
||||
if let hir::GenericBound::Trait(ref ptr, ..) = *bound {
|
||||
let path = &ptr.trait_ref.path;
|
||||
match_path(path, name) && path.segments.last().map_or(false, |s| {
|
||||
if let Some(ref params) = s.args {
|
||||
if params.parenthesized {
|
||||
false
|
||||
} else {
|
||||
// FIXME(flip1995): messy, improve if there is a better option
|
||||
// in the compiler
|
||||
let types: Vec<_> = params.args.iter().filter_map(|arg| match arg {
|
||||
hir::GenericArg::Type(ty) => Some(ty),
|
||||
_ => None,
|
||||
}).collect();
|
||||
types.len() == 1
|
||||
&& (is_self_ty(&types[0]) || is_ty(&*types[0], self_ty))
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
param.name.ident().name == seg.ident.name
|
||||
&& param.bounds.iter().any(|bound| {
|
||||
if let hir::GenericBound::Trait(ref ptr, ..) = *bound {
|
||||
let path = &ptr.trait_ref.path;
|
||||
match_path(path, name)
|
||||
&& path.segments.last().map_or(false, |s| {
|
||||
if let Some(ref params) = s.args {
|
||||
if params.parenthesized {
|
||||
false
|
||||
} else {
|
||||
// FIXME(flip1995): messy, improve if there is a better option
|
||||
// in the compiler
|
||||
let types: Vec<_> = params
|
||||
.args
|
||||
.iter()
|
||||
.filter_map(|arg| match arg {
|
||||
hir::GenericArg::Type(ty) => Some(ty),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
types.len() == 1 && (is_self_ty(&types[0]) || is_ty(&*types[0], self_ty))
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
},
|
||||
_ => false,
|
||||
})
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir;
|
||||
use crate::rustc::hir::def::Def;
|
||||
use crate::rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
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::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::utils::{match_def_path, opt_def_id, paths, span_lint};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
/// **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
|
||||
// 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::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::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
|
||||
/// `ref`.
|
||||
|
@ -43,7 +44,9 @@ use crate::rustc_errors::Applicability;
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// fn foo(ref x: u8) -> bool { .. }
|
||||
/// fn foo(ref x: u8) -> bool {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub TOPLEVEL_REF_ARG,
|
||||
|
@ -139,7 +142,7 @@ declare_clippy_lint! {
|
|||
/// ```rust
|
||||
/// match v {
|
||||
/// Some(x) => (),
|
||||
/// y @ _ => (), // easier written as `y`,
|
||||
/// y @ _ => (), // easier written as `y`,
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
|
@ -182,7 +185,7 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// f() && g(); // We should write `if f() { g(); }`.
|
||||
/// f() && g(); // We should write `if f() { g(); }`.
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub SHORT_CIRCUIT_STATEMENT,
|
||||
|
@ -266,8 +269,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
}
|
||||
for arg in iter_input_pats(decl, body) {
|
||||
match arg.pat.node {
|
||||
PatKind::Binding(BindingAnnotation::Ref, _, _, _) |
|
||||
PatKind::Binding(BindingAnnotation::RefMut, _, _, _) => {
|
||||
PatKind::Binding(BindingAnnotation::Ref, _, _, _)
|
||||
| PatKind::Binding(BindingAnnotation::RefMut, _, _, _) => {
|
||||
span_lint(
|
||||
cx,
|
||||
TOPLEVEL_REF_ARG,
|
||||
|
@ -372,7 +375,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
}
|
||||
if let Some(name) = get_item_name(cx, expr) {
|
||||
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")
|
||||
{
|
||||
return;
|
||||
|
@ -451,7 +457,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
|
|||
cx,
|
||||
REDUNDANT_PATTERN,
|
||||
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
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -467,7 +476,7 @@ fn check_nan(cx: &LateContext<'_, '_>, path: &Path, expr: &Expr) {
|
|||
CMP_NAN,
|
||||
expr.span,
|
||||
"doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead",
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -477,7 +486,7 @@ fn is_named_constant<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) ->
|
|||
if let Some((_, res)) = constant(cx, cx.tables, expr) {
|
||||
res
|
||||
} else {
|
||||
false
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -502,14 +511,16 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr, other: &Expr) {
|
|||
return;
|
||||
}
|
||||
},
|
||||
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"]) {
|
||||
(cx.tables.expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
|
||||
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"]) {
|
||||
(cx.tables.expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
|
@ -520,18 +531,15 @@ fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr, other: &Expr) {
|
|||
None => return,
|
||||
};
|
||||
|
||||
let deref_arg_impl_partial_eq_other = arg_ty
|
||||
.builtin_deref(true)
|
||||
.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
|
||||
.builtin_deref(true)
|
||||
.map_or(false, |tam| implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty.into()]));
|
||||
let deref_arg_impl_partial_eq_other = arg_ty.builtin_deref(true).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.builtin_deref(true).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()]);
|
||||
|
||||
if !deref_arg_impl_partial_eq_other
|
||||
&& !arg_impl_partial_eq_deref_other
|
||||
&& !arg_impl_partial_eq_other
|
||||
{
|
||||
if !deref_arg_impl_partial_eq_other && !arg_impl_partial_eq_deref_other && !arg_impl_partial_eq_other {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,17 +7,16 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass, LintContext, in_external_macro};
|
||||
use crate::rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::rustc_data_structures::fx::FxHashMap;
|
||||
use if_chain::if_chain;
|
||||
use std::char;
|
||||
use crate::rustc_errors::Applicability;
|
||||
use crate::syntax::ast::*;
|
||||
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::rustc_errors::Applicability;
|
||||
use if_chain::if_chain;
|
||||
use std::char;
|
||||
|
||||
/// **What it does:** Checks for structure field patterns bound to wildcards.
|
||||
///
|
||||
|
@ -206,9 +205,7 @@ struct ReturnVisitor {
|
|||
|
||||
impl ReturnVisitor {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
found_return: false,
|
||||
}
|
||||
Self { found_return: false }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,7 +241,8 @@ impl EarlyLintPass for MiscEarly {
|
|||
fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat, _: &mut bool) {
|
||||
if let PatKind::Struct(ref npat, ref pfields, _) = pat.node {
|
||||
let mut wilds = 0;
|
||||
let type_name = npat.segments
|
||||
let type_name = npat
|
||||
.segments
|
||||
.last()
|
||||
.expect("A path must have at least one segment")
|
||||
.ident
|
||||
|
@ -271,8 +269,10 @@ impl EarlyLintPass for MiscEarly {
|
|||
for field in pfields {
|
||||
match field.node.pat.node {
|
||||
PatKind::Wild => {},
|
||||
_ => if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) {
|
||||
normal.push(n);
|
||||
_ => {
|
||||
if let Ok(n) = cx.sess().source_map().span_to_snippet(field.span) {
|
||||
normal.push(n);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -334,36 +334,42 @@ impl EarlyLintPass for MiscEarly {
|
|||
return;
|
||||
}
|
||||
match expr.node {
|
||||
ExprKind::Call(ref paren, _) => if let ExprKind::Paren(ref closure) = paren.node {
|
||||
if let ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.node {
|
||||
let mut visitor = ReturnVisitor::new();
|
||||
visitor.visit_expr(block);
|
||||
if !visitor.found_return {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
REDUNDANT_CLOSURE_CALL,
|
||||
expr.span,
|
||||
"Try not to call a closure in the expression where it is declared.",
|
||||
|db| if decl.inputs.is_empty() {
|
||||
let hint = snippet(cx, block.span, "..").into_owned();
|
||||
db.span_suggestion_with_applicability(
|
||||
expr.span,
|
||||
"Try doing something like: ",
|
||||
hint,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
},
|
||||
);
|
||||
ExprKind::Call(ref paren, _) => {
|
||||
if let ExprKind::Paren(ref closure) = paren.node {
|
||||
if let ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.node {
|
||||
let mut visitor = ReturnVisitor::new();
|
||||
visitor.visit_expr(block);
|
||||
if !visitor.found_return {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
REDUNDANT_CLOSURE_CALL,
|
||||
expr.span,
|
||||
"Try not to call a closure in the expression where it is declared.",
|
||||
|db| {
|
||||
if decl.inputs.is_empty() {
|
||||
let hint = snippet(cx, block.span, "..").into_owned();
|
||||
db.span_suggestion_with_applicability(
|
||||
expr.span,
|
||||
"Try doing something like: ",
|
||||
hint,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ExprKind::Unary(UnOp::Neg, ref inner) => if let ExprKind::Unary(UnOp::Neg, _) = inner.node {
|
||||
span_lint(
|
||||
cx,
|
||||
DOUBLE_NEG,
|
||||
expr.span,
|
||||
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
|
||||
);
|
||||
ExprKind::Unary(UnOp::Neg, ref inner) => {
|
||||
if let ExprKind::Unary(UnOp::Neg, _) = inner.node {
|
||||
span_lint(
|
||||
cx,
|
||||
DOUBLE_NEG,
|
||||
expr.span,
|
||||
"`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
|
||||
);
|
||||
}
|
||||
},
|
||||
ExprKind::Lit(ref lit) => self.check_lit(cx, lit),
|
||||
_ => (),
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
// This file incorporates work covered by the following copyright and
|
||||
// permission notice:
|
||||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
|
@ -29,13 +28,13 @@
|
|||
//
|
||||
|
||||
use crate::rustc::hir;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, LintContext};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
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;
|
||||
use crate::syntax::attr;
|
||||
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
|
||||
/// (public or private).
|
||||
|
@ -72,12 +71,16 @@ impl MissingDoc {
|
|||
}
|
||||
|
||||
fn doc_hidden(&self) -> bool {
|
||||
*self.doc_hidden_stack
|
||||
.last()
|
||||
.expect("empty doc_hidden_stack")
|
||||
*self.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
|
||||
// documentation is probably not really relevant right now.
|
||||
if cx.sess().opts.test {
|
||||
|
@ -93,9 +96,7 @@ impl MissingDoc {
|
|||
return;
|
||||
}
|
||||
|
||||
let has_doc = attrs
|
||||
.iter()
|
||||
.any(|a| a.is_value_str() && a.name() == "doc");
|
||||
let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc");
|
||||
if !has_doc {
|
||||
span_lint(
|
||||
cx,
|
||||
|
@ -115,12 +116,14 @@ impl LintPass for MissingDoc {
|
|||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
|
||||
fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, attrs: &'tcx [ast::Attribute]) {
|
||||
let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
|
||||
attr.check_name("doc") && match attr.meta_item_list() {
|
||||
None => false,
|
||||
Some(l) => attr::list_contains_name(&l[..], "hidden"),
|
||||
}
|
||||
});
|
||||
let doc_hidden = self.doc_hidden()
|
||||
|| attrs.iter().any(|attr| {
|
||||
attr.check_name("doc")
|
||||
&& match attr.meta_item_list() {
|
||||
None => false,
|
||||
Some(l) => attr::list_contains_name(&l[..], "hidden"),
|
||||
}
|
||||
});
|
||||
self.doc_hidden_stack.push(doc_hidden);
|
||||
}
|
||||
|
||||
|
@ -156,10 +159,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc {
|
|||
hir::ItemKind::Ty(..) => "a type alias",
|
||||
hir::ItemKind::Union(..) => "a union",
|
||||
hir::ItemKind::Existential(..) => "an existential type",
|
||||
hir::ItemKind::ExternCrate(..) |
|
||||
hir::ItemKind::ForeignMod(..) |
|
||||
hir::ItemKind::Impl(..) |
|
||||
hir::ItemKind::Use(..) => return,
|
||||
hir::ItemKind::ExternCrate(..)
|
||||
| hir::ItemKind::ForeignMod(..)
|
||||
| hir::ItemKind::Impl(..)
|
||||
| hir::ItemKind::Use(..) => return,
|
||||
};
|
||||
|
||||
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);
|
||||
match cx.tcx.associated_item(def_id).container {
|
||||
ty::TraitContainer(_) => return,
|
||||
ty::ImplContainer(cid) => if cx.tcx.impl_trait_ref(cid).is_some() {
|
||||
return;
|
||||
ty::ImplContainer(cid) => {
|
||||
if cx.tcx.impl_trait_ref(cid).is_some() {
|
||||
return;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// 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,
|
||||
/// 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
|
||||
/// crates even when LTO is disabled. For these types of crates, enabling this lint might make sense.
|
||||
/// It allows the crate to require all exported methods to be `#[inline]` by default, and then opt
|
||||
/// out for specific methods where this might not make sense.
|
||||
/// crates even when LTO is disabled. For these types of crates, enabling this lint might make
|
||||
/// sense. It allows the crate to require all exported methods to be `#[inline]` by default, and
|
||||
/// then opt out for specific methods where this might not make sense.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
|
@ -79,11 +78,8 @@ declare_clippy_lint! {
|
|||
|
||||
pub struct MissingInline;
|
||||
|
||||
fn check_missing_inline_attrs(cx: &LateContext<'_, '_>,
|
||||
attrs: &[ast::Attribute], sp: Span, desc: &'static str) {
|
||||
let has_inline = attrs
|
||||
.iter()
|
||||
.any(|a| a.name() == "inline" );
|
||||
fn check_missing_inline_attrs(cx: &LateContext<'_, '_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) {
|
||||
let has_inline = attrs.iter().any(|a| a.name() == "inline");
|
||||
if !has_inline {
|
||||
span_lint(
|
||||
cx,
|
||||
|
@ -97,11 +93,9 @@ fn check_missing_inline_attrs(cx: &LateContext<'_, '_>,
|
|||
fn is_executable<'a, 'tcx>(cx: &LateContext<'a, 'tcx>) -> bool {
|
||||
use crate::rustc::session::config::CrateType;
|
||||
|
||||
cx.tcx.sess.crate_types.get().iter().any(|t: &CrateType| {
|
||||
match t {
|
||||
CrateType::Executable => true,
|
||||
_ => false,
|
||||
}
|
||||
cx.tcx.sess.crate_types.get().iter().any(|t: &CrateType| match t {
|
||||
CrateType::Executable => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -125,47 +119,44 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline {
|
|||
let desc = "a function";
|
||||
check_missing_inline_attrs(cx, &it.attrs, it.span, desc);
|
||||
},
|
||||
hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics,
|
||||
ref _bounds, ref trait_items) => {
|
||||
hir::ItemKind::Trait(ref _is_auto, ref _unsafe, ref _generics, ref _bounds, ref trait_items) => {
|
||||
// note: we need to check if the trait is exported so we can't use
|
||||
// `LateLintPass::check_trait_item` here.
|
||||
for tit in trait_items {
|
||||
let tit_ = cx.tcx.hir.trait_item(tit.id);
|
||||
match tit_.node {
|
||||
hir::TraitItemKind::Const(..) |
|
||||
hir::TraitItemKind::Type(..) => {},
|
||||
hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {},
|
||||
hir::TraitItemKind::Method(..) => {
|
||||
if tit.defaultness.has_value() {
|
||||
// trait method with default body needs inline in case
|
||||
// an impl is not provided
|
||||
let desc = "a default trait method";
|
||||
let item = cx.tcx.hir.expect_trait_item(tit.id.node_id);
|
||||
check_missing_inline_attrs(cx, &item.attrs,
|
||||
item.span, desc);
|
||||
check_missing_inline_attrs(cx, &item.attrs, item.span, desc);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Const(..) |
|
||||
hir::ItemKind::Enum(..) |
|
||||
hir::ItemKind::Mod(..) |
|
||||
hir::ItemKind::Static(..) |
|
||||
hir::ItemKind::Struct(..) |
|
||||
hir::ItemKind::TraitAlias(..) |
|
||||
hir::ItemKind::GlobalAsm(..) |
|
||||
hir::ItemKind::Ty(..) |
|
||||
hir::ItemKind::Union(..) |
|
||||
hir::ItemKind::Existential(..) |
|
||||
hir::ItemKind::ExternCrate(..) |
|
||||
hir::ItemKind::ForeignMod(..) |
|
||||
hir::ItemKind::Impl(..) |
|
||||
hir::ItemKind::Use(..) => {},
|
||||
},
|
||||
hir::ItemKind::Const(..)
|
||||
| hir::ItemKind::Enum(..)
|
||||
| hir::ItemKind::Mod(..)
|
||||
| hir::ItemKind::Static(..)
|
||||
| hir::ItemKind::Struct(..)
|
||||
| hir::ItemKind::TraitAlias(..)
|
||||
| hir::ItemKind::GlobalAsm(..)
|
||||
| hir::ItemKind::Ty(..)
|
||||
| hir::ItemKind::Union(..)
|
||||
| hir::ItemKind::Existential(..)
|
||||
| hir::ItemKind::ExternCrate(..)
|
||||
| hir::ItemKind::ForeignMod(..)
|
||||
| hir::ItemKind::Impl(..)
|
||||
| hir::ItemKind::Use(..) => {},
|
||||
};
|
||||
}
|
||||
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
@ -177,9 +168,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline {
|
|||
|
||||
let desc = match impl_item.node {
|
||||
hir::ImplItemKind::Method(..) => "a method",
|
||||
hir::ImplItemKind::Const(..) |
|
||||
hir::ImplItemKind::Type(_) |
|
||||
hir::ImplItemKind::Existential(_) => return,
|
||||
hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) | hir::ImplItemKind::Existential(_) => return,
|
||||
};
|
||||
|
||||
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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir;
|
||||
use crate::rustc::hir::intravisit;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
|
||||
use crate::rustc::ty;
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::utils::{higher, span_lint};
|
||||
|
||||
/// **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,
|
||||
"generally you want to avoid `&mut &mut _` if possible",
|
||||
);
|
||||
} else if let ty::Ref(
|
||||
_,
|
||||
_,
|
||||
hir::MutMutable,
|
||||
) = self.cx.tables.expr_ty(e).sty
|
||||
{
|
||||
} else if let ty::Ref(_, _, hir::MutMutable) = self.cx.tables.expr_ty(e).sty {
|
||||
span_lint(
|
||||
self.cx,
|
||||
MUT_MUT,
|
||||
|
@ -109,8 +103,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
|
|||
if let hir::TyKind::Rptr(
|
||||
_,
|
||||
hir::MutTy {
|
||||
mutbl: hir::MutMutable,
|
||||
..
|
||||
mutbl: hir::MutMutable, ..
|
||||
},
|
||||
) = pty.node
|
||||
{
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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::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;
|
||||
|
||||
/// **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! {
|
||||
pub UNNECESSARY_MUT_PASSED,
|
||||
style,
|
||||
"an argument passed as a mutable reference although the callee only demands an \
|
||||
immutable reference"
|
||||
"an argument passed as a mutable reference although the callee only demands an immutable reference"
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct UnnecessaryMutPassed;
|
||||
|
||||
|
@ -47,13 +44,15 @@ impl LintPass for UnnecessaryMutPassed {
|
|||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed {
|
||||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
|
||||
match e.node {
|
||||
ExprKind::Call(ref fn_expr, ref arguments) => if let ExprKind::Path(ref path) = fn_expr.node {
|
||||
check_arguments(
|
||||
cx,
|
||||
arguments,
|
||||
cx.tables.expr_ty(fn_expr),
|
||||
&print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)),
|
||||
);
|
||||
ExprKind::Call(ref fn_expr, ref arguments) => {
|
||||
if let ExprKind::Path(ref path) = fn_expr.node {
|
||||
check_arguments(
|
||||
cx,
|
||||
arguments,
|
||||
cx.tables.expr_ty(fn_expr),
|
||||
&print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)),
|
||||
);
|
||||
}
|
||||
},
|
||||
ExprKind::MethodCall(ref path, _, ref arguments) => {
|
||||
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();
|
||||
for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
|
||||
match parameter.sty {
|
||||
ty::Ref(
|
||||
_,
|
||||
_,
|
||||
MutImmutable,
|
||||
) |
|
||||
ty::RawPtr(ty::TypeAndMut {
|
||||
mutbl: MutImmutable,
|
||||
..
|
||||
}) => if let ExprKind::AddrOf(MutMutable, _) = argument.node {
|
||||
span_lint(
|
||||
cx,
|
||||
UNNECESSARY_MUT_PASSED,
|
||||
argument.span,
|
||||
&format!("The function/method `{}` doesn't need a mutable reference", name),
|
||||
);
|
||||
ty::Ref(_, _, MutImmutable)
|
||||
| ty::RawPtr(ty::TypeAndMut {
|
||||
mutbl: MutImmutable, ..
|
||||
}) => {
|
||||
if let ExprKind::AddrOf(MutMutable, _) = argument.node {
|
||||
span_lint(
|
||||
cx,
|
||||
UNNECESSARY_MUT_PASSED,
|
||||
argument.span,
|
||||
&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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! Checks for uses of mutex where an atomic value could be used
|
||||
//!
|
||||
//! 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::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::utils::{match_type, paths, span_lint};
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! Checks for needless boolean results of if-else expressions
|
||||
//!
|
||||
//! This lint is **warn** by default
|
||||
|
@ -34,13 +33,16 @@ use crate::utils::{in_macro, snippet_with_applicability, span_lint, span_lint_an
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// if x { false } else { true }
|
||||
/// if x {
|
||||
/// false
|
||||
/// } else {
|
||||
/// true
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub NEEDLESS_BOOL,
|
||||
complexity,
|
||||
"if-statements with plain booleans in the then- and else-clause, e.g. \
|
||||
`if p { true } else { false }`"
|
||||
"if-statements with plain booleans in the then- and else-clause, e.g. `if p { true } else { false }`"
|
||||
}
|
||||
|
||||
/// **What it does:** Checks for expressions of the form `x == true` (or vice
|
||||
|
@ -52,7 +54,7 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// if x == true { } // could be `if x { }`
|
||||
/// if x == true {} // could be `if x { }`
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub BOOL_COMPARISON,
|
||||
|
@ -142,7 +144,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
|
|||
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;
|
||||
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
|
||||
(Bool(true), Other) => {
|
||||
|
@ -208,14 +217,16 @@ enum Expression {
|
|||
fn fetch_bool_block(block: &Block) -> Expression {
|
||||
match (&*block.stmts, block.expr.as_ref()) {
|
||||
(&[], Some(e)) => fetch_bool_expr(&**e),
|
||||
(&[ref e], None) => if let StmtKind::Semi(ref e, _) = e.node {
|
||||
if let ExprKind::Ret(_) = e.node {
|
||||
fetch_bool_expr(&**e)
|
||||
(&[ref e], None) => {
|
||||
if let StmtKind::Semi(ref e, _) = e.node {
|
||||
if let ExprKind::Ret(_) = e.node {
|
||||
fetch_bool_expr(&**e)
|
||||
} else {
|
||||
Expression::Other
|
||||
}
|
||||
} else {
|
||||
Expression::Other
|
||||
}
|
||||
} else {
|
||||
Expression::Other
|
||||
},
|
||||
_ => Expression::Other,
|
||||
}
|
||||
|
@ -224,10 +235,12 @@ fn fetch_bool_block(block: &Block) -> Expression {
|
|||
fn fetch_bool_expr(expr: &Expr) -> Expression {
|
||||
match expr.node {
|
||||
ExprKind::Block(ref block, _) => fetch_bool_block(block),
|
||||
ExprKind::Lit(ref lit_ptr) => if let LitKind::Bool(value) = lit_ptr.node {
|
||||
Expression::Bool(value)
|
||||
} else {
|
||||
Expression::Other
|
||||
ExprKind::Lit(ref lit_ptr) => {
|
||||
if let LitKind::Bool(value) = lit_ptr.node {
|
||||
Expression::Bool(value)
|
||||
} else {
|
||||
Expression::Other
|
||||
}
|
||||
},
|
||||
ExprKind::Ret(Some(ref expr)) => match fetch_bool_expr(expr) {
|
||||
Expression::Bool(value) => Expression::RetBool(value),
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! Checks for needless address of operations (`&`)
|
||||
//!
|
||||
//! This lint is **warn** by default
|
||||
|
@ -18,8 +17,8 @@ use crate::rustc::ty;
|
|||
use crate::rustc::ty::adjustment::{Adjust, Adjustment};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::rustc_errors::Applicability;
|
||||
use crate::utils::{in_macro, snippet_opt, span_lint_and_then};
|
||||
use crate::syntax::ast::NodeId;
|
||||
use crate::utils::{in_macro, snippet_opt, span_lint_and_then};
|
||||
use if_chain::if_chain;
|
||||
|
||||
/// **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 {
|
||||
for adj3 in cx.tables.expr_adjustments(e).windows(3) {
|
||||
if let [Adjustment {
|
||||
kind: Adjust::Deref(_),
|
||||
..
|
||||
kind: Adjust::Deref(_), ..
|
||||
}, Adjustment {
|
||||
kind: Adjust::Deref(_),
|
||||
..
|
||||
kind: Adjust::Deref(_), ..
|
||||
}, Adjustment {
|
||||
kind: Adjust::Borrow(_),
|
||||
..
|
||||
|
|
|
@ -7,17 +7,16 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! Checks for useless borrowed references.
|
||||
//!
|
||||
//! 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::{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::utils::{in_macro, snippet, span_lint_and_then};
|
||||
use if_chain::if_chain;
|
||||
|
||||
/// **What it does:** Checks for useless borrowed references.
|
||||
///
|
||||
|
@ -48,8 +47,8 @@ use crate::rustc_errors::Applicability;
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// let mut v = Vec::<String>::new();
|
||||
/// let _ = v.iter_mut().filter(|&ref a| a.is_empty());
|
||||
/// let mut v = Vec::<String>::new();
|
||||
/// let _ = v.iter_mut().filter(|&ref a| a.is_empty());
|
||||
/// ```
|
||||
/// This closure takes a reference on something that has been matched as a
|
||||
/// reference and
|
||||
|
@ -89,7 +88,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrowedRef {
|
|||
|db| {
|
||||
let hint = snippet(cx, spanned_name.span, "..").into_owned();
|
||||
db.span_suggestion_with_applicability(
|
||||
pat.span,
|
||||
pat.span,
|
||||
"try removing the `&ref` part and just keep",
|
||||
hint,
|
||||
Applicability::MachineApplicable, // snippet
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! Checks for continue statements in loops that are redundant.
|
||||
//!
|
||||
//! For example, the lint would catch
|
||||
|
@ -181,7 +180,6 @@ impl EarlyLintPass for NeedlessContinue {
|
|||
/// - The expression is a `continue` node.
|
||||
/// - The expression node is a block with the first statement being a
|
||||
/// `continue`.
|
||||
///
|
||||
fn needless_continue_in_else(else_expr: &ast::Expr) -> bool {
|
||||
match else_expr.node {
|
||||
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 {
|
||||
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 {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
|
||||
if let ast::ExprKind::Continue(_) = e.node {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
})
|
||||
|
@ -208,10 +208,10 @@ where
|
|||
F: FnMut(&ast::Block),
|
||||
{
|
||||
match expr.node {
|
||||
ast::ExprKind::While(_, ref loop_block, _) |
|
||||
ast::ExprKind::WhileLet(_, _, ref loop_block, _) |
|
||||
ast::ExprKind::ForLoop(_, _, ref loop_block, _) |
|
||||
ast::ExprKind::Loop(ref loop_block, _) => func(loop_block),
|
||||
ast::ExprKind::While(_, ref loop_block, _)
|
||||
| ast::ExprKind::WhileLet(_, _, ref loop_block, _)
|
||||
| ast::ExprKind::ForLoop(_, _, ref loop_block, _)
|
||||
| ast::ExprKind::Loop(ref loop_block, _) => func(loop_block),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
@ -224,7 +224,6 @@ where
|
|||
/// - The `if` condition expression,
|
||||
/// - The `then` block, and
|
||||
/// - The `else` expression.
|
||||
///
|
||||
fn with_if_expr<F>(stmt: &ast::Stmt, mut func: F)
|
||||
where
|
||||
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 \
|
||||
block, like so:\n";
|
||||
|
||||
|
||||
fn emit_warning<'a>(ctx: &EarlyContext<'_>, data: &'a LintData<'_>, header: &str, typ: LintType) {
|
||||
// snip is the whole *help* message that appears after the warning.
|
||||
// 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);
|
||||
}
|
||||
|
||||
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 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
|
||||
}
|
||||
|
||||
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 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,
|
||||
};
|
||||
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) {
|
||||
emit_warning(ctx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
|
||||
}
|
||||
|
@ -369,9 +380,9 @@ fn check_and_warn<'a>(ctx: &EarlyContext<'_>, expr: &'a ast::Expr) {
|
|||
/// e.g., the string
|
||||
///
|
||||
/// ```
|
||||
/// {
|
||||
/// let x = 5;
|
||||
/// }
|
||||
/// {
|
||||
/// let x = 5;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// is transformed to
|
||||
|
@ -413,7 +424,6 @@ pub fn erode_from_back(s: &str) -> String {
|
|||
/// inside_a_block();
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub fn erode_from_front(s: &str) -> String {
|
||||
s.chars()
|
||||
.skip_while(|c| c.is_whitespace())
|
||||
|
|
|
@ -7,27 +7,28 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use matches::matches;
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::hir::intravisit::FnKind;
|
||||
use crate::rustc::hir::*;
|
||||
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::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::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_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
|
||||
/// consuming them in its
|
||||
|
@ -67,7 +68,13 @@ impl LintPass for NeedlessPassByValue {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
@ -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_once_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());
|
||||
|
@ -125,7 +132,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
|
|||
.filter(|p| !p.is_global())
|
||||
.filter_map(|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;
|
||||
}
|
||||
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.erase_late_bound_regions(&fn_sig);
|
||||
|
||||
for (idx, ((input, &ty), arg)) in decl.inputs
|
||||
.iter()
|
||||
.zip(fn_sig.inputs())
|
||||
.zip(&body.arguments)
|
||||
.enumerate()
|
||||
{
|
||||
for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(&body.arguments).enumerate() {
|
||||
// All spans generated from a proc-macro invocation are the same...
|
||||
if span == input.span {
|
||||
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 whose reference also fulfills its bound.
|
||||
// (e.g. `std::convert::AsRef`, `serde::Serialize`)
|
||||
// * Exclude a type whose reference also fulfills its bound. (e.g. `std::convert::AsRef`,
|
||||
// `serde::Serialize`)
|
||||
let (implements_borrow_trait, all_borrowable_trait) = {
|
||||
let preds = preds
|
||||
.iter()
|
||||
|
@ -183,17 +187,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
|
|||
|
||||
(
|
||||
preds.iter().any(|t| t.def_id() == borrow_trait),
|
||||
!preds.is_empty() && preds.iter().all(|t| {
|
||||
let ty_params = &t.skip_binder().trait_ref.substs.iter().skip(1)
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
implements_trait(
|
||||
cx,
|
||||
cx.tcx.mk_imm_ref(&RegionKind::ReErased, ty),
|
||||
t.def_id(),
|
||||
ty_params
|
||||
)
|
||||
}),
|
||||
!preds.is_empty()
|
||||
&& preds.iter().all(|t| {
|
||||
let ty_params = &t
|
||||
.skip_binder()
|
||||
.trait_ref
|
||||
.substs
|
||||
.iter()
|
||||
.skip(1)
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
implements_trait(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 decl_without_init(&mut self, _: NodeId, _: Span) {}
|
||||
}
|
||||
|
||||
|
||||
fn unwrap_downcast_or_interior<'a, 'tcx>(mut cmt: &'a mc::cmt_<'tcx>) -> mc::cmt_<'tcx> {
|
||||
loop {
|
||||
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(),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,10 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// 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::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::ty;
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::utils::span_lint;
|
||||
|
||||
/// **What it does:** Checks for needlessly including a base struct on update
|
||||
|
@ -24,7 +23,11 @@ use crate::utils::span_lint;
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// Point { x: 1, y: 0, ..zero_point }
|
||||
/// Point {
|
||||
/// x: 1,
|
||||
/// y: 0,
|
||||
/// ..zero_point
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub NEEDLESS_UPDATE,
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
@ -61,7 +60,6 @@ impl LintPass for NoNegCompOpForPartialOrd {
|
|||
}
|
||||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NoNegCompOpForPartialOrd {
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
|
||||
if_chain! {
|
||||
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use if_chain::if_chain;
|
||||
use crate::syntax::source_map::{Span, Spanned};
|
||||
use if_chain::if_chain;
|
||||
|
||||
use crate::consts::{self, Constant};
|
||||
use crate::utils::span_lint;
|
||||
|
@ -45,7 +44,14 @@ impl LintPass for NegMultiply {
|
|||
#[allow(clippy::match_same_arms)]
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NegMultiply {
|
||||
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) {
|
||||
(&ExprKind::Unary(..), &ExprKind::Unary(..)) => (),
|
||||
(&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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::def_id::DefId;
|
||||
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::{declare_tool_lint, lint_array};
|
||||
use if_chain::if_chain;
|
||||
use crate::rustc::ty::{self, Ty};
|
||||
use crate::rustc_errors::Applicability;
|
||||
use crate::syntax::source_map::Span;
|
||||
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::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
|
||||
/// 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 {
|
||||
hir::GenericParamKind::Type { .. } => true,
|
||||
_ => false
|
||||
_ => false,
|
||||
}) {
|
||||
// when the result of `new()` depends on a type parameter we should not require
|
||||
// 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) {
|
||||
let self_did = cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id));
|
||||
let self_ty = cx.tcx
|
||||
.type_of(self_did);
|
||||
let self_ty = cx.tcx.type_of(self_did);
|
||||
if_chain! {
|
||||
if same_tys(cx, self_ty, return_ty(cx, id));
|
||||
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,
|
||||
NEW_WITHOUT_DEFAULT_DERIVE,
|
||||
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.suggest_item_with_attr(
|
||||
cx,
|
||||
|
@ -186,7 +187,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
|
|||
cx,
|
||||
NEW_WITHOUT_DEFAULT,
|
||||
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.suggest_prepend_item(
|
||||
cx,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::def::Def;
|
||||
use crate::rustc::hir::{BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource};
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
|
@ -63,37 +62,42 @@ fn has_no_effect(cx: &LateContext<'_, '_>, expr: &Expr) -> bool {
|
|||
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::Repeat(ref inner, _) |
|
||||
ExprKind::Cast(ref inner, _) |
|
||||
ExprKind::Type(ref inner, _) |
|
||||
ExprKind::Unary(_, ref inner) |
|
||||
ExprKind::Field(ref inner, _) |
|
||||
ExprKind::AddrOf(_, ref inner) |
|
||||
ExprKind::Box(ref inner) => has_no_effect(cx, inner),
|
||||
ExprKind::Repeat(ref inner, _)
|
||||
| ExprKind::Cast(ref inner, _)
|
||||
| ExprKind::Type(ref inner, _)
|
||||
| ExprKind::Unary(_, ref inner)
|
||||
| ExprKind::Field(ref inner, _)
|
||||
| ExprKind::AddrOf(_, ref inner)
|
||||
| ExprKind::Box(ref inner) => has_no_effect(cx, inner),
|
||||
ExprKind::Struct(_, ref fields, ref 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),
|
||||
None => true,
|
||||
}
|
||||
!has_drop(cx, expr)
|
||||
&& fields.iter().all(|field| has_no_effect(cx, &field.expr))
|
||||
&& match *base {
|
||||
Some(ref base) => has_no_effect(cx, base),
|
||||
None => true,
|
||||
}
|
||||
},
|
||||
ExprKind::Call(ref callee, ref args) => if let ExprKind::Path(ref qpath) = callee.node {
|
||||
let def = cx.tables.qpath_def(qpath, callee.hir_id);
|
||||
match def {
|
||||
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) => {
|
||||
!has_drop(cx, expr) && args.iter().all(|arg| has_no_effect(cx, arg))
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
},
|
||||
ExprKind::Block(ref block, _) => {
|
||||
block.stmts.is_empty() && if let Some(ref expr) = block.expr {
|
||||
has_no_effect(cx, expr)
|
||||
ExprKind::Call(ref callee, ref args) => {
|
||||
if let ExprKind::Path(ref qpath) = callee.node {
|
||||
let def = cx.tables.qpath_def(qpath, callee.hir_id);
|
||||
match def {
|
||||
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..) => {
|
||||
!has_drop(cx, expr) && args.iter().all(|arg| has_no_effect(cx, arg))
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
ExprKind::Block(ref block, _) => {
|
||||
block.stmts.is_empty()
|
||||
&& if let Some(ref expr) = block.expr {
|
||||
has_no_effect(cx, expr)
|
||||
} 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>> {
|
||||
if in_macro(expr.span) {
|
||||
return None;
|
||||
|
@ -150,37 +153,34 @@ fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr) -> Option<Vec
|
|||
Some(vec![&**a, &**b])
|
||||
},
|
||||
ExprKind::Array(ref v) | ExprKind::Tup(ref v) => Some(v.iter().collect()),
|
||||
ExprKind::Repeat(ref inner, _) |
|
||||
ExprKind::Cast(ref inner, _) |
|
||||
ExprKind::Type(ref inner, _) |
|
||||
ExprKind::Unary(_, ref inner) |
|
||||
ExprKind::Field(ref inner, _) |
|
||||
ExprKind::AddrOf(_, ref 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) {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
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 {
|
||||
let def = cx.tables.qpath_def(qpath, callee.hir_id);
|
||||
match def {
|
||||
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..)
|
||||
if !has_drop(cx, expr) =>
|
||||
{
|
||||
Some(args.iter().collect())
|
||||
},
|
||||
_ => None,
|
||||
ExprKind::Repeat(ref inner, _)
|
||||
| ExprKind::Cast(ref inner, _)
|
||||
| ExprKind::Type(ref inner, _)
|
||||
| ExprKind::Unary(_, ref inner)
|
||||
| ExprKind::Field(ref inner, _)
|
||||
| ExprKind::AddrOf(_, ref 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) {
|
||||
None
|
||||
} else {
|
||||
Some(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 {
|
||||
let def = cx.tables.qpath_def(qpath, callee.hir_id);
|
||||
match def {
|
||||
Def::Struct(..) | Def::Variant(..) | Def::StructCtor(..) | Def::VariantCtor(..)
|
||||
if !has_drop(cx, expr) =>
|
||||
{
|
||||
Some(args.iter().collect())
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
},
|
||||
ExprKind::Block(ref block, _) => {
|
||||
if block.stmts.is_empty() {
|
||||
|
|
|
@ -7,22 +7,21 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! Checks for uses of const which the type is not Freeze (Cell-free).
|
||||
//!
|
||||
//! 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::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::{self, TypeFlags};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::rustc_errors::Applicability;
|
||||
use crate::rustc_typeck::hir_ty_to_ty;
|
||||
use crate::syntax_pos::{DUMMY_SP, Span};
|
||||
use std::ptr;
|
||||
use crate::syntax_pos::{Span, DUMMY_SP};
|
||||
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
|
||||
/// mutable (e.g. contains a `Cell`, `Mutex`, `AtomicXxxx` etc).
|
||||
|
@ -42,11 +41,11 @@ use crate::utils::{in_constant, in_macro, is_copy, span_lint_and_then};
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// use std::sync::atomic::{Ordering::SeqCst, AtomicUsize};
|
||||
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||
///
|
||||
/// // Bad.
|
||||
/// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
|
||||
/// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
|
||||
/// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
|
||||
/// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
|
||||
///
|
||||
/// // Good.
|
||||
|
@ -74,11 +73,11 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// use std::sync::atomic::{Ordering::SeqCst, AtomicUsize};
|
||||
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||
/// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
|
||||
///
|
||||
/// // Bad.
|
||||
/// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
|
||||
/// CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
|
||||
/// assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
|
||||
///
|
||||
/// // Good.
|
||||
|
@ -94,16 +93,9 @@ declare_clippy_lint! {
|
|||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Source {
|
||||
Item {
|
||||
item: Span,
|
||||
},
|
||||
Assoc {
|
||||
item: Span,
|
||||
ty: Span,
|
||||
},
|
||||
Expr {
|
||||
expr: Span,
|
||||
},
|
||||
Item { item: Span },
|
||||
Assoc { item: Span, ty: Span },
|
||||
Expr { expr: Span },
|
||||
}
|
||||
|
||||
impl Source {
|
||||
|
@ -123,11 +115,7 @@ impl Source {
|
|||
}
|
||||
}
|
||||
|
||||
fn verify_ty_bound<'a, 'tcx>(
|
||||
cx: &LateContext<'a, 'tcx>,
|
||||
ty: ty::Ty<'tcx>,
|
||||
source: Source,
|
||||
) {
|
||||
fn verify_ty_bound<'a, 'tcx>(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) {
|
||||
// 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
|
||||
|
@ -149,22 +137,19 @@ fn verify_ty_bound<'a, 'tcx>(
|
|||
"static".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
},
|
||||
Source::Assoc { ty: ty_span, .. } => {
|
||||
if ty.flags.contains(TypeFlags::HAS_FREE_LOCAL_NAMES) {
|
||||
db.span_help(ty_span, &format!("consider requiring `{}` to be `Copy`", ty));
|
||||
}
|
||||
}
|
||||
},
|
||||
Source::Expr { .. } => {
|
||||
db.help(
|
||||
"assign this const to a local or static variable, and use the variable here",
|
||||
);
|
||||
}
|
||||
db.help("assign this const to a local or static variable, and use the variable here");
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
pub struct 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) {
|
||||
if let TraitItemKind::Const(hir_ty, ..) = &trait_item.node {
|
||||
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.
|
||||
if let ItemKind::Impl(_, _, _, _, None, _, _) = item.node {
|
||||
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(..) => {
|
||||
// `&e` => `e` must be referenced
|
||||
needs_check_adjustment = false;
|
||||
}
|
||||
},
|
||||
ExprKind::Field(..) => {
|
||||
dereferenced_expr = parent_expr;
|
||||
needs_check_adjustment = true;
|
||||
}
|
||||
},
|
||||
ExprKind::Index(e, _) if ptr::eq(&**e, cur_expr) => {
|
||||
// `e[i]` => desugared to `*Index::index(&e, i)`,
|
||||
// meaning `e` must be referenced.
|
||||
// no need to go further up since a method call is involved now.
|
||||
needs_check_adjustment = false;
|
||||
break;
|
||||
}
|
||||
},
|
||||
ExprKind::Unary(UnDeref, _) => {
|
||||
// `*e` => desugared to `*Deref::deref(&e)`,
|
||||
// meaning `e` must be referenced.
|
||||
// no need to go further up since a method call is involved now.
|
||||
needs_check_adjustment = false;
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ => break,
|
||||
}
|
||||
cur_expr = parent_expr;
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::lint::{LintArray, LintPass, EarlyContext, EarlyLintPass};
|
||||
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
|
||||
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::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::utils::{span_lint, span_lint_and_then};
|
||||
|
||||
|
@ -116,9 +115,11 @@ impl<'a, 'tcx: 'a, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
|||
fn visit_pat(&mut self, pat: &'tcx Pat) {
|
||||
match pat.node {
|
||||
PatKind::Ident(_, ident, _) => self.check_name(ident.span, ident.name),
|
||||
PatKind::Struct(_, ref fields, _) => for field in fields {
|
||||
if !field.node.is_shorthand {
|
||||
self.visit_pat(&field.node.pat);
|
||||
PatKind::Struct(_, ref fields, _) => {
|
||||
for field in fields {
|
||||
if !field.node.is_shorthand {
|
||||
self.visit_pat(&field.node.pat);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => walk_pat(self, pat),
|
||||
|
@ -155,7 +156,10 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
|||
self.0.cx,
|
||||
MANY_SINGLE_CHAR_NAMES,
|
||||
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 {
|
||||
let mut interned_chars = interned_name.chars();
|
||||
let mut existing_chars = existing_name.interned.chars();
|
||||
let first_i = interned_chars
|
||||
.next()
|
||||
.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 first_i = interned_chars.next().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();
|
||||
|
||||
if eq_or_numeric((first_i, first_e)) {
|
||||
let last_i = interned_chars
|
||||
.next_back()
|
||||
.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");
|
||||
let last_i = interned_chars.next_back().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 interned_chars
|
||||
.zip(existing_chars)
|
||||
.filter(|&ie| !eq_or_numeric(ie))
|
||||
.count() != 1
|
||||
.count()
|
||||
!= 1
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -227,7 +224,8 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
|||
let second_last_e = existing_chars
|
||||
.next_back()
|
||||
.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)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
} else {
|
||||
let second_i = interned_chars
|
||||
.next()
|
||||
.expect("we know we have at least two chars");
|
||||
let second_e = existing_chars
|
||||
.next()
|
||||
.expect("we know we have at least two chars");
|
||||
if !eq_or_numeric((second_i, second_e)) || second_i == '_'
|
||||
let second_i = interned_chars.next().expect("we know we have at least two chars");
|
||||
let second_e = existing_chars.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)
|
||||
{
|
||||
// allowed similarity x_foo, y_foo
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
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::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.
|
||||
///
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::{Expr, ExprKind};
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
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) {
|
||||
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 {
|
||||
span_lint(
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
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::utils::{span_lint, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
|
||||
/// **What it does:** Detects classic underflow/overflow checks.
|
||||
///
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use if_chain::if_chain;
|
||||
use crate::syntax::ast::LitKind;
|
||||
use crate::syntax::ptr::P;
|
||||
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 if_chain::if_chain;
|
||||
|
||||
/// **What it does:** Checks for missing parameters in `panic!`.
|
||||
///
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::hir::*;
|
||||
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::utils::{is_automatically_derived, span_lint};
|
||||
use if_chain::if_chain;
|
||||
|
||||
/// **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
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
|
||||
use crate::rustc::{declare_tool_lint, lint_array};
|
||||
use crate::rustc_errors::Applicability;
|
||||
|
@ -115,7 +114,10 @@ impl EarlyLintPass for Precedence {
|
|||
expr.span,
|
||||
"unary minus has lower precedence than method call",
|
||||
"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,
|
||||
);
|
||||
},
|
||||
|
|
|
@ -7,22 +7,21 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
//! Checks for usage of `&Vec[_]` and `&String`.
|
||||
|
||||
use std::borrow::Cow;
|
||||
use crate::rustc::hir::*;
|
||||
use crate::rustc::hir::QPath;
|
||||
use crate::rustc::hir::*;
|
||||
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::{declare_tool_lint, lint_array};
|
||||
use crate::rustc_errors::Applicability;
|
||||
use crate::syntax::ast::NodeId;
|
||||
use crate::syntax::source_map::Span;
|
||||
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::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`
|
||||
/// or `&Vec` unless the references are mutable. It will also suggest you
|
||||
|
@ -57,8 +56,7 @@ use crate::rustc_errors::Applicability;
|
|||
declare_clippy_lint! {
|
||||
pub PTR_ARG,
|
||||
style,
|
||||
"fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` \
|
||||
instead, respectively"
|
||||
"fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively"
|
||||
}
|
||||
|
||||
/// **What it does:** This lint checks for equality comparisons with `ptr::null`
|
||||
|
@ -71,7 +69,9 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// if x == ptr::null { .. }
|
||||
/// if x == ptr::null {
|
||||
/// ..
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
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();
|
||||
|
||||
for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() {
|
||||
if let ty::Ref(
|
||||
_,
|
||||
ty,
|
||||
MutImmutable
|
||||
) = ty.sty
|
||||
{
|
||||
if let ty::Ref(_, ty, MutImmutable) = ty.sty {
|
||||
if match_type(cx, ty, &paths::VEC) {
|
||||
let mut ty_snippet = None;
|
||||
if_chain! {
|
||||
|
@ -193,19 +188,18 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
|
|||
|db| {
|
||||
if let Some(ref snippet) = ty_snippet {
|
||||
db.span_suggestion_with_applicability(
|
||||
arg.span,
|
||||
"change this to",
|
||||
format!("&[{}]", snippet),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
arg.span,
|
||||
"change this to",
|
||||
format!("&[{}]", snippet),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
}
|
||||
for (clonespan, suggestion) in spans {
|
||||
db.span_suggestion_with_applicability(
|
||||
clonespan,
|
||||
&snippet_opt(cx, clonespan).map_or(
|
||||
"change the call to".into(),
|
||||
|x| Cow::Owned(format!("change `{}` to", x)),
|
||||
),
|
||||
&snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
|
||||
Cow::Owned(format!("change `{}` to", x))
|
||||
}),
|
||||
suggestion.into(),
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
|
@ -230,10 +224,9 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl, fn_id: NodeId, opt_body_id:
|
|||
for (clonespan, suggestion) in spans {
|
||||
db.span_suggestion_short_with_applicability(
|
||||
clonespan,
|
||||
&snippet_opt(cx, clonespan).map_or(
|
||||
"change the call to".into(),
|
||||
|x| Cow::Owned(format!("change `{}` to", x)),
|
||||
),
|
||||
&snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
|
||||
Cow::Owned(format!("change `{}` to", x))
|
||||
}),
|
||||
suggestion.into(),
|
||||
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 Some((out, MutMutable, _)) = get_rptr_lm(ty) {
|
||||
let mut immutables = vec![];
|
||||
for (_, ref mutbl, ref argspan) in decl.inputs
|
||||
for (_, ref mutbl, ref argspan) in decl
|
||||
.inputs
|
||||
.iter()
|
||||
.filter_map(|ty| get_rptr_lm(ty))
|
||||
.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() {
|
||||
return;
|
||||
}
|
||||
span_lint_and_then(cx, MUT_FROM_REF, ty.span, "mutable borrow from immutable input(s)", |db| {
|
||||
let ms = MultiSpan::from_spans(immutables);
|
||||
db.span_note(ms, "immutable borrow here");
|
||||
});
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MUT_FROM_REF,
|
||||
ty.span,
|
||||
"mutable borrow from immutable input(s)",
|
||||
|db| {
|
||||
let ms = MultiSpan::from_spans(immutables);
|
||||
db.span_note(ms, "immutable borrow here");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use crate::rustc::{declare_tool_lint, hir, lint, lint_array};
|
||||
use crate::rustc_errors::Applicability;
|
||||
use crate::utils;
|
||||
|
@ -27,7 +26,9 @@ use std::fmt;
|
|||
/// let ptr = vec.as_ptr();
|
||||
/// let offset = 1_usize;
|
||||
///
|
||||
/// unsafe { ptr.offset(offset as isize); }
|
||||
/// unsafe {
|
||||
/// ptr.offset(offset as isize);
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Could be written:
|
||||
|
@ -37,7 +38,9 @@ use std::fmt;
|
|||
/// let ptr = vec.as_ptr();
|
||||
/// let offset = 1_usize;
|
||||
///
|
||||
/// unsafe { ptr.add(offset); }
|
||||
/// unsafe {
|
||||
/// ptr.add(offset);
|
||||
/// }
|
||||
/// ```
|
||||
declare_clippy_lint! {
|
||||
pub PTR_OFFSET_WITH_CAST,
|
||||
|
@ -82,7 +85,6 @@ impl<'a, 'tcx> lint::LateLintPass<'a, 'tcx> for Pass {
|
|||
} else {
|
||||
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?
|
||||
fn is_expr_ty_usize<'a, 'tcx>(
|
||||
cx: &lint::LateContext<'a, 'tcx>,
|
||||
expr: &hir::Expr,
|
||||
) -> bool {
|
||||
fn is_expr_ty_usize<'a, 'tcx>(cx: &lint::LateContext<'a, 'tcx>, expr: &hir::Expr) -> bool {
|
||||
cx.tables.expr_ty(expr) == cx.tcx.types.usize
|
||||
}
|
||||
|
||||
// Is the type of the expression a raw pointer?
|
||||
fn is_expr_ty_raw_ptr<'a, 'tcx>(
|
||||
cx: &lint::LateContext<'a, 'tcx>,
|
||||
expr: &hir::Expr,
|
||||
) -> bool {
|
||||
fn is_expr_ty_raw_ptr<'a, 'tcx>(cx: &lint::LateContext<'a, 'tcx>, expr: &hir::Expr) -> bool {
|
||||
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