Merge pull request #3465 from flip1995/rustfmt

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

View file

@ -30,6 +30,7 @@ before_install:
install:
- |
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

View file

@ -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, dont report any suggestions). You can avoid prolonging
@ -246,7 +260,8 @@ Contributions to Clippy should be made in the form of GitHub pull requests. Each
be reviewed by a core contributor (someone with permission to land patches) and either landed in the
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 -->

View file

@ -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());

View file

@ -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...

View file

@ -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));
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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 => (),
}
}

View file

@ -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

View file

@ -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,)
}
}

View file

@ -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
),
);
}

View file

@ -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 }
}
}

View file

@ -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);

View file

@ -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, &[]))
}

View file

@ -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,

View file

@ -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,
}
}

View file

@ -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("/*")
}

View file

@ -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);

View file

@ -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,
}

View file

@ -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)) {

View file

@ -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`.

View file

@ -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
),
);
}

View file

@ -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(..) => {},
}
}
}
}
}
}

View file

@ -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;
}
}
}
}
},
_ => (),

View file

@ -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
}

View file

@ -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!(==)
},
_ => (),
};
}

View file

@ -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 = &params[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 = &params[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 = &params[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 = &params[1];
if let ExprKind::Paren(_) = param.node {
span_lint(
cx,
DOUBLE_PARENS,
param.span,
"Consider removing unnecessary double parentheses",
);
}
}
},
_ => {},

View file

@ -7,13 +7,12 @@
// option. This file may not be copied, modified, or distributed
// 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,

View file

@ -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,
);
}

View file

@ -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::*;

View file

@ -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",
);
});
}
}

View file

@ -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 {

View file

@ -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,
}

View file

@ -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");
}
}
}

View file

@ -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",
);
}
}
}

View file

@ -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,
}
}

View file

@ -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,

View file

@ -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()

View file

@ -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)
}
},
_ => (),
}

View file

@ -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;

View file

@ -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),

View file

@ -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)]

View file

@ -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>,

View file

@ -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
);
});
}
}
},
_ => (),

View file

@ -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
// its 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

View file

@ -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)
},
_ => {},
}
}

View file

@ -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
);
});
}
}
}
}

View file

@ -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`.
///

View file

@ -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::*;

View file

@ -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),

View file

@ -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};

View file

@ -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
_ => (),
}

View file

@ -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");
},
)
})

View file

@ -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
///

View file

@ -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
);
},
);
}
}

View file

@ -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.
///

View file

@ -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(..)));

View file

@ -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;

View file

@ -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),

View file

@ -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
}

View file

@ -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")
}
},
}
}

View file

@ -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(&lt) {
return true;
Some(lts) => {
for lt in lts {
if !allowed_lts.contains(&lt) {
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",
);
}
}

View file

@ -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(),

View file

@ -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.",
);
}
}

View file

@ -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,
)
}

View file

@ -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);
}
});
}

View file

@ -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())),

View file

@ -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};

View file

@ -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

View file

@ -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};

View file

@ -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, &note);
} 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,
})

View file

@ -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};

View file

@ -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

View file

@ -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;
}

View file

@ -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),
_ => (),

View file

@ -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;
}
},
}

View file

@ -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);

View file

@ -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
{

View file

@ -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),
);
}
},
_ => (),
}

View file

@ -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};

View file

@ -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),

View file

@ -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(_),
..

View file

@ -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

View file

@ -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())

View file

@ -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(),
}
};
}
}

View file

@ -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,

View file

@ -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! {

View file

@ -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),

View file

@ -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,

View file

@ -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() {

View file

@ -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;

View file

@ -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

View file

@ -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.
///

View file

@ -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(

View file

@ -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.
///

View file

@ -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!`.
///

View file

@ -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`.
///

View file

@ -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,
);
},

View file

@ -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");
},
);
}
}
}

View file

@ -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