Merge remote-tracking branch 'upstream/master' into clippy-fix

This commit is contained in:
Jane Lusby 2020-04-15 08:24:13 -07:00
commit 0441525690
256 changed files with 2953 additions and 2085 deletions

4
.gitattributes vendored
View File

@ -1,5 +1,3 @@
[attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4
* text=auto eol=lf
*.rs rust
*.rs text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4
*.fixed linguist-language=Rust

10
.github/deploy.sh vendored
View File

@ -17,6 +17,11 @@ if [[ -n $TAG_NAME ]]; then
ln -s "$TAG_NAME" out/stable
fi
if [[ $BETA = "true" ]]; then
echo "Update documentation for the beta release"
cp -r out/master out/beta
fi
# Generate version index that is shown as root index page
cp util/gh-pages/versions.html out/index.html
@ -35,12 +40,15 @@ fi
if [[ -n $TAG_NAME ]]; then
# Add the new dir
git add $TAG_NAME
git add "$TAG_NAME"
# Update the symlink
git add stable
# Update versions file
git add versions.json
git commit -m "Add documentation for ${TAG_NAME} release: ${SHA}"
elif [[ $BETA = "true" ]]; then
git add beta
git commit -m "Automatic deploy to GitHub Pages (beta): ${SHA}"
else
git add .
git commit -m "Automatic deploy to GitHub Pages: ${SHA}"

View File

@ -234,7 +234,8 @@ jobs:
- 'rust-lang/cargo'
- 'rust-lang/rls'
- 'rust-lang/chalk'
- 'rust-lang/rustfmt'
# FIXME: Disabled until https://github.com/rust-lang/rust/issues/71077 is fixed
# - 'rust-lang/rustfmt'
- 'Marwes/combine'
- 'Geal/nom'
- 'rust-lang/stdarch'

View File

@ -38,8 +38,8 @@ jobs:
run: cargo build --features deny-warnings
working-directory: clippy_dev
- name: Test limit-stderr-length
run: cargo dev --limit-stderr-length
- name: Test limit_stderr_length
run: cargo dev limit_stderr_length
- name: Test update_lints
run: cargo dev update_lints --check

View File

@ -4,6 +4,7 @@ on:
push:
branches:
- master
- beta
tags:
- rust-1.**
@ -34,6 +35,9 @@ jobs:
run: |
TAG=$(basename ${{ github.ref }})
echo "::set-env name=TAG_NAME::$TAG"
- name: Set beta to true
if: github.ref == 'refs/heads/beta'
run: echo "::set-env name=BETA::true"
- name: Deploy
run: |
eval "$(ssh-agent -s)"

View File

@ -1271,6 +1271,7 @@ Released 2018-09-13
[`float_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_arithmetic
[`float_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp
[`float_cmp_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp_const
[`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
[`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
[`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
[`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
@ -1432,6 +1433,7 @@ Released 2018-09-13
[`range_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_plus_one
[`range_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_step_by_zero
[`range_zip_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#range_zip_with_len
[`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
[`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
@ -1446,6 +1448,7 @@ Released 2018-09-13
[`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
[`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
[`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used
[`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
[`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
[`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else
[`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used
@ -1540,6 +1543,7 @@ Released 2018-09-13
[`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box
[`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask
[`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
[`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
[`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition
[`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop
[`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator

View File

@ -36,7 +36,8 @@ High level approach:
### Finding something to fix/improve
All issues on Clippy are mentored, if you want help with a bug just ask @Manishearth, @llogiq, @mcarton or @oli-obk.
All issues on Clippy are mentored, if you want help with a bug just ask
@Manishearth, @flip1995, @phansch or @yaahc.
Some issues are easier than others. The [`good first issue`] label can be used to find the easy issues.
If you want to work on an issue, please leave a comment so that we can assign it to you!
@ -70,7 +71,7 @@ an AST expression). `match_def_path()` in Clippy's `utils` module can also be us
[`T-AST`]: https://github.com/rust-lang/rust-clippy/labels/T-AST
[`T-middle`]: https://github.com/rust-lang/rust-clippy/labels/T-middle
[`E-medium`]: https://github.com/rust-lang/rust-clippy/labels/E-medium
[`ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ty
[`ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty
[nodes in the AST docs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/
[deep-nesting]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/mem_forget.rs#L29-L43
[if_chain]: https://docs.rs/if_chain/*/if_chain
@ -78,8 +79,7 @@ an AST expression). `match_def_path()` in Clippy's `utils` module can also be us
## Writing code
Have a look at the [docs for writing lints][adding_lints] for more details. [Llogiq's blog post on lints]
is also a nice primer to lint-writing, though it does get into advanced stuff and may be a bit outdated.
Have a look at the [docs for writing lints][adding_lints] for more details.
If you want to add a new lint or change existing ones apart from bugfixing, it's
also a good idea to give the [stability guarantees][rfc_stability] and
@ -87,7 +87,6 @@ also a good idea to give the [stability guarantees][rfc_stability] and
quick read.
[adding_lints]: https://github.com/rust-lang/rust-clippy/blob/master/doc/adding_lints.md
[Llogiq's blog post on lints]: https://llogiq.github.io/2015/06/04/workflows.html
[clippy_rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md
[rfc_stability]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#stability-guarantees
[rfc_lint_cats]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories
@ -223,7 +222,7 @@ You can find the Clippy bors queue [here][homu_queue].
If you have @bors permissions, you can find an overview of the available
commands [here][homu_instructions].
[triage]: https://forge.rust-lang.org/triage-procedure.html
[triage]: https://forge.rust-lang.org/release/triage-procedure.html
[l-crash]: https://github.com/rust-lang/rust-clippy/labels/L-crash%20%3Aboom%3A
[l-bug]: https://github.com/rust-lang/rust-clippy/labels/L-bug%20%3Abeetle%3A
[homu]: https://github.com/rust-lang/homu

View File

@ -42,7 +42,7 @@ lazy_static = "1.0"
[dev-dependencies]
cargo_metadata = "0.9.0"
compiletest_rs = { version = "0.4.0", features = ["tmp"] }
compiletest_rs = { version = "0.5.0", features = ["tmp"] }
tester = "0.7"
lazy_static = "1.0"
clippy-mini-macro-test = { version = "0.2", path = "mini-macro" }

View File

@ -5,7 +5,7 @@
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
[There are 362 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
[There are over 350 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
@ -90,14 +90,6 @@ Note that this is still experimental and only supported on the nightly channel:
cargo fix -Z unstable-options --clippy
```
#### Running only a single lint
If you care only about the warnings of a single lint and want to ignore everything else, you
can first deny all the clippy lints and then explicitly enable the lint(s) you care about:
````
cargo clippy -- -Aclippy::all -Wclippy::useless_format
````
### Running Clippy from the command line without installing it
To have cargo compile your crate with Clippy without Clippy installation
@ -183,6 +175,8 @@ If you do not want to include your lint levels in your code, you can globally en
flags to Clippy during the run: `cargo clippy -- -A clippy::lint_name` will run Clippy with `lint_name` disabled and
`cargo clippy -- -W clippy::lint_name` will run it with that enabled. This also works with lint groups. For example you
can run Clippy with warnings for all lints enabled: `cargo clippy -- -W clippy::pedantic`
If you care only about a single lint, you can allow all others and then explicitly reenable
the lint(s) you are interested in: `cargo clippy -- -Aclippy::all -Wclippy::useless_format -Wclippy::...`
## Contributing

View File

@ -7,7 +7,7 @@ edition = "2018"
[dependencies]
bytecount = "0.6"
clap = "2.33"
itertools = "0.8"
itertools = "0.9"
regex = "1"
lazy_static = "1.0"
shell-escape = "0.1"

View File

@ -1,4 +1,4 @@
use clippy_dev::clippy_project_root;
use crate::clippy_project_root;
use shell_escape::escape;
use std::ffi::OsStr;
use std::io;

View File

@ -9,6 +9,11 @@ use std::fs;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;
pub mod fmt;
pub mod new_lint;
pub mod stderr_length_check;
pub mod update_lints;
lazy_static! {
static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(
r#"(?x)
@ -57,13 +62,25 @@ impl Lint {
}
/// Returns all non-deprecated lints and non-internal lints
pub fn usable_lints(lints: impl Iterator<Item = Self>) -> impl Iterator<Item = Self> {
lints.filter(|l| l.deprecation.is_none() && !l.is_internal())
#[must_use]
pub fn usable_lints(lints: &[Self]) -> Vec<Self> {
lints
.iter()
.filter(|l| l.deprecation.is_none() && !l.group.starts_with("internal"))
.cloned()
.collect()
}
/// Returns all internal lints (not `internal_warn` lints)
pub fn internal_lints(lints: impl Iterator<Item = Self>) -> impl Iterator<Item = Self> {
lints.filter(|l| l.group == "internal")
#[must_use]
pub fn internal_lints(lints: &[Self]) -> Vec<Self> {
lints.iter().filter(|l| l.group == "internal").cloned().collect()
}
/// Returns all deprecated lints
#[must_use]
pub fn deprecated_lints(lints: &[Self]) -> Vec<Self> {
lints.iter().filter(|l| l.deprecation.is_some()).cloned().collect()
}
/// Returns the lints in a `HashMap`, grouped by the different lint groups
@ -71,71 +88,45 @@ impl Lint {
pub fn by_lint_group(lints: impl Iterator<Item = Self>) -> HashMap<String, Vec<Self>> {
lints.map(|lint| (lint.group.to_string(), lint)).into_group_map()
}
#[must_use]
pub fn is_internal(&self) -> bool {
self.group.starts_with("internal")
}
}
/// Generates the Vec items for `register_lint_group` calls in `clippy_lints/src/lib.rs`.
#[must_use]
pub fn gen_lint_group_list(lints: Vec<Lint>) -> Vec<String> {
pub fn gen_lint_group_list<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
lints
.into_iter()
.filter_map(|l| {
if l.deprecation.is_some() {
None
} else {
Some(format!(" LintId::of(&{}::{}),", l.module, l.name.to_uppercase()))
}
})
.map(|l| format!(" LintId::of(&{}::{}),", l.module, l.name.to_uppercase()))
.sorted()
.collect::<Vec<String>>()
}
/// Generates the `pub mod module_name` list in `clippy_lints/src/lib.rs`.
#[must_use]
pub fn gen_modules_list(lints: Vec<Lint>) -> Vec<String> {
pub fn gen_modules_list<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
lints
.into_iter()
.filter_map(|l| {
if l.is_internal() || l.deprecation.is_some() {
None
} else {
Some(l.module)
}
})
.map(|l| &l.module)
.unique()
.map(|module| format!("pub mod {};", module))
.map(|module| format!("mod {};", module))
.sorted()
.collect::<Vec<String>>()
}
/// Generates the list of lint links at the bottom of the README
#[must_use]
pub fn gen_changelog_lint_list(lints: Vec<Lint>) -> Vec<String> {
let mut lint_list_sorted: Vec<Lint> = lints;
lint_list_sorted.sort_by_key(|l| l.name.clone());
lint_list_sorted
.iter()
.filter_map(|l| {
if l.is_internal() {
None
} else {
Some(format!("[`{}`]: {}#{}", l.name, DOCS_LINK, l.name))
}
})
pub fn gen_changelog_lint_list<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
lints
.sorted_by_key(|l| &l.name)
.map(|l| format!("[`{}`]: {}#{}", l.name, DOCS_LINK, l.name))
.collect()
}
/// Generates the `register_removed` code in `./clippy_lints/src/lib.rs`.
#[must_use]
pub fn gen_deprecated(lints: &[Lint]) -> Vec<String> {
pub fn gen_deprecated<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
lints
.iter()
.filter_map(|l| {
l.clone().deprecation.map(|depr_text| {
.flat_map(|l| {
l.deprecation
.clone()
.map(|depr_text| {
vec![
" store.register_removed(".to_string(),
format!(" \"clippy::{}\",", l.name),
@ -143,24 +134,17 @@ pub fn gen_deprecated(lints: &[Lint]) -> Vec<String> {
" );".to_string(),
]
})
.expect("only deprecated lints should be passed")
})
.flatten()
.collect::<Vec<String>>()
}
#[must_use]
pub fn gen_register_lint_list(lints: &[Lint]) -> Vec<String> {
pub fn gen_register_lint_list<'a>(lints: impl Iterator<Item = &'a Lint>) -> Vec<String> {
let pre = " store.register_lints(&[".to_string();
let post = " ]);".to_string();
let mut inner = lints
.iter()
.filter_map(|l| {
if !l.is_internal() && l.deprecation.is_none() {
Some(format!(" &{}::{},", l.module, l.name.to_uppercase()))
} else {
None
}
})
.map(|l| format!(" &{}::{},", l.module, l.name.to_uppercase()))
.sorted()
.collect::<Vec<String>>();
inner.insert(0, pre);
@ -434,7 +418,7 @@ fn test_usable_lints() {
None,
"module_name",
)];
assert_eq!(expected, Lint::usable_lints(lints.into_iter()).collect::<Vec<Lint>>());
assert_eq!(expected, Lint::usable_lints(&lints));
}
#[test]
@ -464,13 +448,12 @@ fn test_gen_changelog_lint_list() {
let lints = vec![
Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
Lint::new("incorrect_internal", "internal_style", "abc", None, "module_name"),
];
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()),
];
assert_eq!(expected, gen_changelog_lint_list(lints));
assert_eq!(expected, gen_changelog_lint_list(lints.iter()));
}
#[test]
@ -490,7 +473,6 @@ fn test_gen_deprecated() {
Some("will be removed"),
"module_name",
),
Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
];
let expected: Vec<String> = vec![
" store.register_removed(",
@ -505,22 +487,24 @@ fn test_gen_deprecated() {
.into_iter()
.map(String::from)
.collect();
assert_eq!(expected, gen_deprecated(&lints));
assert_eq!(expected, gen_deprecated(lints.iter()));
}
#[test]
#[should_panic]
fn test_gen_deprecated_fail() {
let lints = vec![Lint::new("should_assert_eq2", "group2", "abc", None, "module_name")];
let _ = gen_deprecated(lints.iter());
}
#[test]
fn test_gen_modules_list() {
let lints = vec![
Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
Lint::new("should_assert_eq2", "group2", "abc", Some("abc"), "deprecated"),
Lint::new("incorrect_stuff", "group3", "abc", None, "another_module"),
Lint::new("incorrect_internal", "internal_style", "abc", None, "module_name"),
];
let expected = vec![
"pub mod another_module;".to_string(),
"pub mod module_name;".to_string(),
];
assert_eq!(expected, gen_modules_list(lints));
let expected = vec!["mod another_module;".to_string(), "mod module_name;".to_string()];
assert_eq!(expected, gen_modules_list(lints.iter()));
}
#[test]
@ -528,7 +512,6 @@ fn test_gen_lint_group_list() {
let lints = vec![
Lint::new("abc", "group1", "abc", None, "module_name"),
Lint::new("should_assert_eq", "group1", "abc", None, "module_name"),
Lint::new("should_assert_eq2", "group2", "abc", Some("abc"), "deprecated"),
Lint::new("internal", "internal_style", "abc", None, "module_name"),
];
let expected = vec![
@ -536,5 +519,5 @@ fn test_gen_lint_group_list() {
" LintId::of(&module_name::INTERNAL),".to_string(),
" LintId::of(&module_name::SHOULD_ASSERT_EQ),".to_string(),
];
assert_eq!(expected, gen_lint_group_list(lints));
assert_eq!(expected, gen_lint_group_list(lints.iter()));
}

View File

@ -1,21 +1,7 @@
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
use clap::{App, Arg, SubCommand};
use clippy_dev::{
gather_all, gen_changelog_lint_list, gen_deprecated, gen_lint_group_list, gen_modules_list, gen_register_lint_list,
replace_region_in_file, Lint, DOCS_LINK,
};
use std::path::Path;
mod fmt;
mod new_lint;
mod stderr_length_check;
#[derive(Clone, Copy, PartialEq)]
enum UpdateMode {
Check,
Change,
}
use clippy_dev::{fmt, new_lint, stderr_length_check, update_lints};
fn main() {
let matches = App::new("Clippy developer tooling")
@ -97,28 +83,23 @@ fn main() {
.takes_value(true),
),
)
.arg(
Arg::with_name("limit-stderr-length")
.long("limit-stderr-length")
.help("Ensures that stderr files do not grow longer than a certain amount of lines."),
.subcommand(
SubCommand::with_name("limit_stderr_length")
.about("Ensures that stderr files do not grow longer than a certain amount of lines."),
)
.get_matches();
if matches.is_present("limit-stderr-length") {
stderr_length_check::check();
}
match matches.subcommand() {
("fmt", Some(matches)) => {
fmt::run(matches.is_present("check"), matches.is_present("verbose"));
},
("update_lints", Some(matches)) => {
if matches.is_present("print-only") {
print_lints();
update_lints::print_lints();
} else if matches.is_present("check") {
update_lints(UpdateMode::Check);
update_lints::run(update_lints::UpdateMode::Check);
} else {
update_lints(UpdateMode::Change);
update_lints::run(update_lints::UpdateMode::Change);
}
},
("new_lint", Some(matches)) => {
@ -127,168 +108,13 @@ fn main() {
matches.value_of("name"),
matches.value_of("category"),
) {
Ok(_) => update_lints(UpdateMode::Change),
Ok(_) => update_lints::run(update_lints::UpdateMode::Change),
Err(e) => eprintln!("Unable to create lint: {}", e),
}
},
("limit_stderr_length", _) => {
stderr_length_check::check();
},
_ => {},
}
}
fn print_lints() {
let lint_list = gather_all();
let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list).collect();
let usable_lint_count = usable_lints.len();
let grouped_by_lint_group = Lint::by_lint_group(usable_lints.into_iter());
for (lint_group, mut lints) in grouped_by_lint_group {
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,
lint.name,
lint.desc
);
}
}
println!("there are {} lints", usable_lint_count);
}
#[allow(clippy::too_many_lines)]
fn update_lints(update_mode: UpdateMode) {
let lint_list: Vec<Lint> = gather_all().collect();
let internal_lints = Lint::internal_lints(lint_list.clone().into_iter());
let usable_lints: Vec<Lint> = Lint::usable_lints(lint_list.clone().into_iter()).collect();
let usable_lint_count = usable_lints.len();
let mut sorted_usable_lints = usable_lints.clone();
sorted_usable_lints.sort_by_key(|lint| lint.name.clone());
let mut file_change = replace_region_in_file(
Path::new("src/lintlist/mod.rs"),
"begin lint list",
"end lint list",
false,
update_mode == UpdateMode::Change,
|| {
format!(
"pub const ALL_LINTS: [Lint; {}] = {:#?};",
sorted_usable_lints.len(),
sorted_usable_lints
)
.lines()
.map(ToString::to_string)
.collect::<Vec<_>>()
},
)
.changed;
file_change |= replace_region_in_file(
Path::new("README.md"),
&format!(r#"\[There are \d+ lints included in this crate!\]\({}\)"#, DOCS_LINK),
"",
true,
update_mode == UpdateMode::Change,
|| {
vec![format!(
"[There are {} lints included in this crate!]({})",
usable_lint_count, DOCS_LINK
)]
},
)
.changed;
file_change |= replace_region_in_file(
Path::new("CHANGELOG.md"),
"<!-- begin autogenerated links to lint list -->",
"<!-- end autogenerated links to lint list -->",
false,
update_mode == UpdateMode::Change,
|| gen_changelog_lint_list(lint_list.clone()),
)
.changed;
file_change |= replace_region_in_file(
Path::new("clippy_lints/src/lib.rs"),
"begin deprecated lints",
"end deprecated lints",
false,
update_mode == UpdateMode::Change,
|| gen_deprecated(&lint_list),
)
.changed;
file_change |= replace_region_in_file(
Path::new("clippy_lints/src/lib.rs"),
"begin register lints",
"end register lints",
false,
update_mode == UpdateMode::Change,
|| gen_register_lint_list(&lint_list),
)
.changed;
file_change |= replace_region_in_file(
Path::new("clippy_lints/src/lib.rs"),
"begin lints modules",
"end lints modules",
false,
update_mode == UpdateMode::Change,
|| gen_modules_list(lint_list.clone()),
)
.changed;
// Generate lists of lints in the clippy::all lint group
file_change |= replace_region_in_file(
Path::new("clippy_lints/src/lib.rs"),
r#"store.register_group\(true, "clippy::all""#,
r#"\]\);"#,
false,
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();
gen_lint_group_list(all_group_lints)
},
)
.changed;
// Generate the list of lints for all other lint groups
for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) {
file_change |= replace_region_in_file(
Path::new("clippy_lints/src/lib.rs"),
&format!("store.register_group\\(true, \"clippy::{}\"", lint_group),
r#"\]\);"#,
false,
update_mode == UpdateMode::Change,
|| gen_lint_group_list(lints.clone()),
)
.changed;
}
if update_mode == UpdateMode::Check && file_change {
println!(
"Not all lints defined properly. \
Please run `cargo dev update_lints` to make sure all lints are defined properly."
);
std::process::exit(1);
}
}

View File

@ -1,10 +1,15 @@
use clippy_dev::clippy_project_root;
use crate::clippy_project_root;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::io::ErrorKind;
use std::path::Path;
/// Creates files required to implement and test a new lint and runs `update_lints`.
///
/// # Errors
///
/// This function errors, if the files couldn't be created
pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> Result<(), io::Error> {
let pass = pass.expect("`pass` argument is validated by clap");
let lint_name = lint_name.expect("`name` argument is validated by clap");

View File

@ -1,11 +1,9 @@
use crate::clippy_project_root;
use std::ffi::OsStr;
use std::fs;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;
use clippy_dev::clippy_project_root;
// The maximum length allowed for stderr files.
//
// We limit this because small files are easier to deal with than bigger files.

View File

@ -0,0 +1,162 @@
use crate::{
gather_all, gen_changelog_lint_list, gen_deprecated, gen_lint_group_list, gen_modules_list, gen_register_lint_list,
replace_region_in_file, Lint, DOCS_LINK,
};
use std::path::Path;
#[derive(Clone, Copy, PartialEq)]
pub enum UpdateMode {
Check,
Change,
}
#[allow(clippy::too_many_lines)]
pub fn run(update_mode: UpdateMode) {
let lint_list: Vec<Lint> = gather_all().collect();
let internal_lints = Lint::internal_lints(&lint_list);
let deprecated_lints = Lint::deprecated_lints(&lint_list);
let usable_lints = Lint::usable_lints(&lint_list);
let mut sorted_usable_lints = usable_lints.clone();
sorted_usable_lints.sort_by_key(|lint| lint.name.clone());
let usable_lint_count = round_to_fifty(usable_lints.len());
let mut file_change = replace_region_in_file(
Path::new("src/lintlist/mod.rs"),
"begin lint list",
"end lint list",
false,
update_mode == UpdateMode::Change,
|| {
format!("pub static ref ALL_LINTS: Vec<Lint> = vec!{:#?};", sorted_usable_lints)
.lines()
.map(ToString::to_string)
.collect::<Vec<_>>()
},
)
.changed;
file_change |= replace_region_in_file(
Path::new("README.md"),
&format!(
r#"\[There are over \d+ lints included in this crate!\]\({}\)"#,
DOCS_LINK
),
"",
true,
update_mode == UpdateMode::Change,
|| {
vec![format!(
"[There are over {} lints included in this crate!]({})",
usable_lint_count, DOCS_LINK
)]
},
)
.changed;
file_change |= replace_region_in_file(
Path::new("CHANGELOG.md"),
"<!-- begin autogenerated links to lint list -->",
"<!-- end autogenerated links to lint list -->",
false,
update_mode == UpdateMode::Change,
|| gen_changelog_lint_list(usable_lints.iter().chain(deprecated_lints.iter())),
)
.changed;
file_change |= replace_region_in_file(
Path::new("clippy_lints/src/lib.rs"),
"begin deprecated lints",
"end deprecated lints",
false,
update_mode == UpdateMode::Change,
|| gen_deprecated(deprecated_lints.iter()),
)
.changed;
file_change |= replace_region_in_file(
Path::new("clippy_lints/src/lib.rs"),
"begin register lints",
"end register lints",
false,
update_mode == UpdateMode::Change,
|| gen_register_lint_list(usable_lints.iter().chain(internal_lints.iter())),
)
.changed;
file_change |= replace_region_in_file(
Path::new("clippy_lints/src/lib.rs"),
"begin lints modules",
"end lints modules",
false,
update_mode == UpdateMode::Change,
|| gen_modules_list(usable_lints.iter()),
)
.changed;
// Generate lists of lints in the clippy::all lint group
file_change |= replace_region_in_file(
Path::new("clippy_lints/src/lib.rs"),
r#"store.register_group\(true, "clippy::all""#,
r#"\]\);"#,
false,
update_mode == UpdateMode::Change,
|| {
// clippy::all should only include the following lint groups:
let all_group_lints = usable_lints.iter().filter(|l| {
l.group == "correctness" || l.group == "style" || l.group == "complexity" || l.group == "perf"
});
gen_lint_group_list(all_group_lints)
},
)
.changed;
// Generate the list of lints for all other lint groups
for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) {
file_change |= replace_region_in_file(
Path::new("clippy_lints/src/lib.rs"),
&format!("store.register_group\\(true, \"clippy::{}\"", lint_group),
r#"\]\);"#,
false,
update_mode == UpdateMode::Change,
|| gen_lint_group_list(lints.iter()),
)
.changed;
}
if update_mode == UpdateMode::Check && file_change {
println!(
"Not all lints defined properly. \
Please run `cargo dev update_lints` to make sure all lints are defined properly."
);
std::process::exit(1);
}
}
pub fn print_lints() {
let lint_list: Vec<Lint> = gather_all().collect();
let usable_lints = Lint::usable_lints(&lint_list);
let usable_lint_count = usable_lints.len();
let grouped_by_lint_group = Lint::by_lint_group(usable_lints.into_iter());
for (lint_group, mut lints) in grouped_by_lint_group {
if lint_group == "Deprecated" {
continue;
}
println!("\n## {}", lint_group);
lints.sort_by_key(|l| l.name.clone());
for lint in lints {
println!("* [{}]({}#{}) ({})", lint.name, DOCS_LINK, lint.name, lint.desc);
}
}
println!("there are {} lints", usable_lint_count);
}
fn round_to_fifty(count: usize) -> usize {
count / 50 * 50
}

View File

@ -1,6 +1,6 @@
use rustc::lint::in_external_macro;
use rustc_ast::ast::{Expr, ExprKind};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use crate::utils::span_lint_and_help;

View File

@ -3,11 +3,11 @@ use crate::utils::{
};
use crate::utils::{higher, sugg};
use if_chain::if_chain;
use rustc::hir::map::Map;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
@ -77,7 +77,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
},
hir::ExprKind::Assign(assignee, e, _) => {
if let hir::ExprKind::Binary(op, l, r) = &e.kind {
#[allow(clippy::cognitive_complexity)]
let lint = |assignee: &hir::Expr<'_>, rhs: &hir::Expr<'_>| {
let ty = cx.tables.expr_ty(assignee);
let rty = cx.tables.expr_ty(rhs);

View File

@ -1,9 +1,9 @@
use crate::utils::{match_def_path, span_lint_and_help};
use if_chain::if_chain;
use rustc::ty;
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {

View File

@ -6,8 +6,6 @@ use crate::utils::{
span_lint_and_then, without_block_comments,
};
use if_chain::if_chain;
use rustc::lint::in_external_macro;
use rustc::ty;
use rustc_ast::ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_errors::Applicability;
@ -15,6 +13,8 @@ use rustc_hir::{
Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind,
};
use rustc_lint::{CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;

View File

@ -87,7 +87,7 @@ declare_clippy_lint! {
/// **Example:**
/// ```rust
/// # let x = 1;
/// if x & 0x1111 == 0 { }
/// if x & 0b1111 == 0 { }
/// ```
pub VERBOSE_BIT_MASK,
style,

View File

@ -1,10 +1,10 @@
use crate::utils::{differing_macro_contexts, higher, snippet_block_with_applicability, span_lint, span_lint_and_sugg};
use rustc::hir::map::Map;
use rustc::lint::in_external_macro;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{BlockCheckMode, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {

View File

@ -1,14 +1,14 @@
use crate::utils::{
get_trait_def_id, implements_trait, in_macro, match_type, paths, snippet_opt, span_lint_and_sugg,
get_trait_def_id, implements_trait, in_macro, is_type_diagnostic_item, paths, snippet_opt, span_lint_and_sugg,
span_lint_and_then, SpanlessEq,
};
use if_chain::if_chain;
use rustc::hir::map::Map;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
@ -249,7 +249,9 @@ fn simplify_not(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option<String> {
},
ExprKind::MethodCall(path, _, args) if args.len() == 1 => {
let type_of_receiver = cx.tables.expr_ty(&args[0]);
if !match_type(cx, type_of_receiver, &paths::OPTION) && !match_type(cx, type_of_receiver, &paths::RESULT) {
if !is_type_diagnostic_item(cx, type_of_receiver, sym!(option_type))
&& !is_type_diagnostic_item(cx, type_of_receiver, sym!(result_type))
{
return None;
}
METHODS_WITH_NEGATION

View File

@ -3,11 +3,11 @@ use crate::utils::{
span_lint_and_sugg, walk_ptrs_ty,
};
use if_chain::if_chain;
use rustc::ty;
use rustc_ast::ast::{Name, UintTy};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {

View File

@ -1,11 +1,11 @@
//! lint on manually implemented checked conversions that could be transformed into `try_from`
use if_chain::if_chain;
use rustc::lint::in_external_macro;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use crate::utils::{snippet_with_applicability, span_lint_and_sugg, SpanlessEq};
@ -21,7 +21,7 @@ declare_clippy_lint! {
/// ```rust
/// # let foo: u32 = 5;
/// # let _ =
/// foo <= i32::max_value() as u32
/// foo <= i32::MAX as u32
/// # ;
/// ```
///
@ -179,7 +179,7 @@ impl ConversionType {
}
}
/// Check for `expr <= (to_type::max_value() as from_type)`
/// Check for `expr <= (to_type::MAX as from_type)`
fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
if_chain! {
if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind;
@ -194,7 +194,7 @@ fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
}
}
/// Check for `expr >= 0|(to_type::min_value() as from_type)`
/// Check for `expr >= 0|(to_type::MIN as from_type)`
fn check_lower_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
fn check_function<'a>(candidate: &'a Expr<'a>, check: &'a Expr<'a>) -> Option<Conversion<'a>> {
(check_lower_bound_zero(candidate, check)).or_else(|| (check_lower_bound_min(candidate, check)))
@ -222,7 +222,7 @@ fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> O
}
}
/// Check for `expr >= (to_type::min_value() as from_type)`
/// Check for `expr >= (to_type::MIN as from_type)`
fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> {
if let Some((from, to)) = get_types_from_cast(check, MIN_VALUE, SINTS) {
Conversion::try_new(candidate, from, to)

View File

@ -1,15 +1,15 @@
//! calculate cognitive complexity and warn about overly complex functions
use rustc::hir::map::Map;
use rustc_ast::ast::Attribute;
use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::BytePos;
use crate::utils::{match_type, paths, snippet_opt, span_lint_and_help, LimitStack};
use crate::utils::{is_type_diagnostic_item, snippet_opt, span_lint_and_help, LimitStack};
declare_clippy_lint! {
/// **What it does:** Checks for methods with high cognitive complexity.
@ -22,7 +22,7 @@ declare_clippy_lint! {
///
/// **Example:** No. You'll see it when you get the warning.
pub COGNITIVE_COMPLEXITY,
complexity,
nursery,
"functions that should be split up into multiple functions"
}
@ -61,7 +61,7 @@ impl CognitiveComplexity {
helper.visit_expr(expr);
let CCHelper { cc, returns } = helper;
let ret_ty = cx.tables.node_type(expr.hir_id);
let ret_adjust = if match_type(cx, ret_ty, &paths::RESULT) {
let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym!(result_type)) {
returns
} else {
#[allow(clippy::integer_division)]

View File

@ -2,14 +2,14 @@
use crate::utils::{clip, higher, sext, unsext};
use if_chain::if_chain;
use rustc::ty::subst::{Subst, SubstsRef};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::{bug, span_bug};
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
use rustc_data_structures::sync::Lrc;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp};
use rustc_lint::LateContext;
use rustc_middle::ty::subst::{Subst, SubstsRef};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_span::symbol::Symbol;
use std::cmp::Ordering::{self, Equal};
use std::convert::TryInto;
@ -268,6 +268,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
}
}
},
ExprKind::Index(ref arr, ref index) => self.index(arr, index),
// TODO: add other expressions.
_ => None,
}
@ -333,7 +334,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
.tcx
.const_eval_resolve(self.param_env, def_id, substs, None, None)
.ok()
.map(|val| rustc::ty::Const::from_value(self.lcx.tcx, val, ty))?;
.map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
let result = miri_to_const(&result);
if result.is_some() {
self.needed_resolution = true;
@ -345,6 +346,31 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
}
}
fn index(&mut self, lhs: &'_ Expr<'_>, index: &'_ Expr<'_>) -> Option<Constant> {
let lhs = self.expr(lhs);
let index = self.expr(index);
match (lhs, index) {
(Some(Constant::Vec(vec)), Some(Constant::Int(index))) => match vec[index as usize] {
Constant::F32(x) => Some(Constant::F32(x)),
Constant::F64(x) => Some(Constant::F64(x)),
_ => None,
},
(Some(Constant::Vec(vec)), _) => {
if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) {
match vec[0] {
Constant::F32(x) => Some(Constant::F32(x)),
Constant::F64(x) => Some(Constant::F64(x)),
_ => None,
}
} else {
None
}
},
_ => None,
}
}
/// A block can only yield a constant if it only has one constant expression.
fn block(&mut self, block: &Block<'_>) -> Option<Constant> {
if block.stmts.is_empty() {
@ -460,7 +486,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> {
}
pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
use rustc::mir::interpret::{ConstValue, Scalar};
use rustc_middle::mir::interpret::{ConstValue, Scalar};
match result.val {
ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data: d, .. })) => match result.ty.kind {
ty::Bool => Some(Constant::Bool(d == 1)),
@ -492,6 +518,41 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
},
_ => None,
},
ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind {
ty::Array(sub_type, len) => match sub_type.kind {
ty::Float(FloatTy::F32) => match miri_to_const(len) {
Some(Constant::Int(len)) => alloc
.inspect_with_undef_and_ptr_outside_interpreter(0..(4 * len as usize))
.to_owned()
.chunks(4)
.map(|chunk| {
Some(Constant::F32(f32::from_le_bytes(
chunk.try_into().expect("this shouldn't happen"),
)))
})
.collect::<Option<Vec<Constant>>>()
.map(Constant::Vec),
_ => None,
},
ty::Float(FloatTy::F64) => match miri_to_const(len) {
Some(Constant::Int(len)) => alloc
.inspect_with_undef_and_ptr_outside_interpreter(0..(8 * len as usize))
.to_owned()
.chunks(8)
.map(|chunk| {
Some(Constant::F64(f64::from_le_bytes(
chunk.try_into().expect("this shouldn't happen"),
)))
})
.collect::<Option<Vec<Constant>>>()
.map(Constant::Vec),
_ => None,
},
// FIXME: implement other array type conversions.
_ => None,
},
_ => None,
},
// FIXME: implement other conversions.
_ => None,
}

View File

@ -1,9 +1,9 @@
use crate::utils::{get_parent_expr, higher, if_sequence, same_tys, snippet, span_lint_and_note, span_lint_and_then};
use crate::utils::{SpanlessEq, SpanlessHash};
use rustc::ty::Ty;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{Arm, Block, Expr, ExprKind, MatchSource, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::Symbol;
use std::collections::hash_map::Entry;

View File

@ -1,8 +1,8 @@
use if_chain::if_chain;
use rustc::ty;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use crate::utils::{any_parent_is_automatically_derived, match_def_path, paths, span_lint_and_sugg};

View File

@ -147,3 +147,11 @@ declare_deprecated_lint! {
pub UNUSED_LABEL,
"this lint has been uplifted to rustc and is now called `unused_labels`"
}
declare_deprecated_lint! {
/// **What it does:** Nothing. This lint has been deprecated.
///
/// **Deprecation reason:** Associated-constants are now preferred.
pub REPLACE_CONSTS,
"associated-constants `MIN`/`MAX` of integers are prefer to `{min,max}_value()` and module constants"
}

View File

@ -1,9 +1,9 @@
use crate::utils::paths;
use crate::utils::{is_automatically_derived, is_copy, match_path, span_lint_and_then};
use if_chain::if_chain;
use rustc::ty::{self, Ty};
use rustc_hir::{Item, ItemKind, TraitRef};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
@ -94,7 +94,8 @@ fn check_hash_peq<'a, 'tcx>(
if_chain! {
if match_path(&trait_ref.path, &paths::HASH);
if let Some(peq_trait_def_id) = cx.tcx.lang_items().eq_trait();
if !&trait_ref.trait_def_id().is_local();
if let Some(def_id) = &trait_ref.trait_def_id();
if !def_id.is_local();
then {
// Look for the PartialEq implementations for `ty`
cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {

View File

@ -1,12 +1,12 @@
use crate::utils::{implements_trait, is_entrypoint_fn, match_type, paths, return_ty, span_lint};
use crate::utils::{implements_trait, is_entrypoint_fn, is_type_diagnostic_item, return_ty, span_lint};
use if_chain::if_chain;
use itertools::Itertools;
use rustc::lint::in_external_macro;
use rustc::ty;
use rustc_ast::ast::{AttrKind, Attribute};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::{BytePos, MultiSpan, Span};
use rustc_span::Pos;
@ -217,7 +217,7 @@ fn lint_for_missing_headers<'a, 'tcx>(
);
}
if !headers.errors {
if match_type(cx, return_ty(cx, hir_id), &paths::RESULT) {
if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
span_lint(
cx,
MISSING_ERRORS_DOC,
@ -229,13 +229,13 @@ fn lint_for_missing_headers<'a, 'tcx>(
if let Some(body_id) = body_id;
if let Some(future) = cx.tcx.lang_items().future_trait();
let def_id = cx.tcx.hir().body_owner_def_id(body_id);
let mir = cx.tcx.optimized_mir(def_id);
let mir = cx.tcx.optimized_mir(def_id.to_def_id());
let ret_ty = mir.return_ty();
if implements_trait(cx, ret_ty, future, &[]);
if let ty::Opaque(_, subs) = ret_ty.kind;
if let Some(gen) = subs.types().next();
if let ty::Generator(_, subs, _) = gen.kind;
if match_type(cx, subs.as_generator().return_ty(), &paths::RESULT);
if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym!(result_type));
then {
span_lint(
cx,

View File

@ -1,8 +1,8 @@
use crate::utils::{is_copy, match_def_path, paths, qpath_res, span_lint_and_note};
use if_chain::if_chain;
use rustc::ty;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {

View File

@ -1,8 +1,8 @@
//! Lint on if expressions with an else if, but without a final else branch.
use rustc::lint::in_external_macro;
use rustc_ast::ast::{Expr, ExprKind};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use crate::utils::span_lint_and_help;

View File

@ -2,11 +2,11 @@ use crate::utils::SpanlessEq;
use crate::utils::{get_item_name, higher, match_type, paths, snippet, snippet_opt};
use crate::utils::{snippet_with_applicability, span_lint_and_then, walk_ptrs_ty};
use if_chain::if_chain;
use rustc::hir::map::Map;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{BorrowKind, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

View File

@ -3,11 +3,11 @@
use crate::consts::{miri_to_const, Constant};
use crate::utils::span_lint;
use rustc::ty;
use rustc::ty::util::IntTypeExt;
use rustc_ast::ast::{IntTy, UintTy};
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::util::IntTypeExt;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use std::convert::TryFrom;
@ -46,12 +46,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant {
for var in def.variants {
if let Some(anon_const) = &var.disr_expr {
let def_id = cx.tcx.hir().body_owner_def_id(anon_const.body);
let mut ty = cx.tcx.type_of(def_id);
let mut ty = cx.tcx.type_of(def_id.to_def_id());
let constant = cx
.tcx
.const_eval_poly(def_id)
.const_eval_poly(def_id.to_def_id())
.ok()
.map(|val| rustc::ty::Const::from_value(cx.tcx, val, ty));
.map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty));
if let Some(Constant::Int(val)) = constant.and_then(miri_to_const) {
if let ty::Adt(adt, _) = ty.kind {
if adt.is_enum() {

View File

@ -1,11 +1,11 @@
use rustc::ty::layout::LayoutOf;
use rustc::ty::{self, Ty};
use rustc_hir::intravisit;
use rustc_hir::{self, Body, FnDecl, HirId, HirIdSet, ItemKind, Node};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_target::abi::LayoutOf;
use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase};
use crate::utils::span_lint;
@ -92,7 +92,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxedLocal {
}
// TODO: Replace with Map::is_argument(..) when it's fixed
fn is_argument(map: rustc::hir::map::Map<'_>, id: HirId) -> bool {
fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool {
match map.find(id) {
Some(Node::Binding(_)) => (),
_ => return false,

View File

@ -1,9 +1,9 @@
use if_chain::if_chain;
use rustc::lint::in_external_macro;
use rustc::ty::{self, Ty};
use rustc_errors::Applicability;
use rustc_hir::{def_id, Expr, ExprKind, Param, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use crate::utils::{

View File

@ -1,10 +1,10 @@
use crate::utils::{get_parent_expr, span_lint, span_lint_and_note};
use if_chain::if_chain;
use rustc::hir::map::Map;
use rustc::ty;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{def, BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {

View File

@ -1,10 +1,12 @@
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, span_lint_and_then, walk_ptrs_ty};
use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT};
use crate::utils::{
is_expn_of, is_type_diagnostic_item, match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty,
};
use if_chain::if_chain;
use rustc::hir::map::Map;
use rustc::ty::{self, Ty};
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;
@ -76,7 +78,9 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
let reciever_ty = walk_ptrs_ty(self.tables.expr_ty(&arglists[0][0]));
if match_type(self.lcx, reciever_ty, &OPTION) || match_type(self.lcx, reciever_ty, &RESULT) {
if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type))
|| is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type))
{
self.result.push(expr.span);
}
}
@ -124,10 +128,3 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it
}
}
}
fn match_type(cx: &LateContext<'_, '_>, ty: Ty<'_>, path: &[&str]) -> bool {
match ty.kind {
ty::Adt(adt, _) => match_def_path(cx, adt.did, path),
_ => false,
}
}

View File

@ -1,12 +1,12 @@
use crate::utils::{numeric_literal, span_lint_and_sugg};
use if_chain::if_chain;
use rustc::ty;
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use std::{f32, f64, fmt};
use std::fmt;
declare_clippy_lint! {
/// **What it does:** Checks for float literals with a precision greater

View File

@ -4,10 +4,10 @@ use crate::consts::{
};
use crate::utils::{higher, numeric_literal, span_lint_and_sugg, sugg, SpanlessEq};
use if_chain::if_chain;
use rustc::ty;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;

View File

@ -91,7 +91,7 @@ fn on_argumentv1_new<'a, 'tcx>(
if pats.len() == 1;
then {
let ty = walk_ptrs_ty(cx.tables.pat_ty(&pats[0]));
if ty.kind != rustc::ty::Str && !match_type(cx, ty, &paths::STRING) {
if ty.kind != rustc_middle::ty::Str && !match_type(cx, ty, &paths::STRING) {
return None;
}
if let ExprKind::Lit(ref lit) = format_args.kind {

View File

@ -1,8 +1,8 @@
use crate::utils::{differing_macro_contexts, snippet_opt, span_lint_and_help, span_lint_and_note};
use if_chain::if_chain;
use rustc::lint::in_external_macro;
use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

View File

@ -3,9 +3,6 @@ use crate::utils::{
must_use_attr, qpath_res, return_ty, snippet, snippet_opt, span_lint, span_lint_and_help, span_lint_and_then,
trait_ref_of_method, type_is_unsafe_function,
};
use rustc::hir::map::Map;
use rustc::lint::in_external_macro;
use rustc::ty::{self, Ty};
use rustc_ast::ast::Attribute;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@ -13,6 +10,9 @@ use rustc_hir as hir;
use rustc_hir::intravisit;
use rustc_hir::{def::Res, def_id::DefId};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_target::spec::abi::Abi;

View File

@ -8,7 +8,6 @@ use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::Symbol;
declare_clippy_lint! {
/// **What it does:** Checks for using `x.get(x.len() - 1)` instead of
@ -51,12 +50,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for GetLastWithLen {
if let ExprKind::MethodCall(ref path, _, ref args) = expr.kind;
// Method name is "get"
if path.ident.name == Symbol::intern("get");
if path.ident.name == sym!(get);
// Argument 0 (the struct we're calling the method on) is a vector
if let Some(struct_calling_on) = args.get(0);
let struct_ty = cx.tables.expr_ty(struct_calling_on);
if is_type_diagnostic_item(cx, struct_ty, Symbol::intern("vec_type"));
if is_type_diagnostic_item(cx, struct_ty, sym!(vec_type));
// Argument to "get" is a subtraction
if let Some(get_index_arg) = args.get(1);
@ -71,7 +70,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for GetLastWithLen {
// LHS of subtraction is "x.len()"
if let ExprKind::MethodCall(arg_lhs_path, _, lhs_args) = &lhs.kind;
if arg_lhs_path.ident.name == Symbol::intern("len");
if arg_lhs_path.ident.name == sym!(len);
if let Some(arg_lhs_struct) = lhs_args.get(0);
// The two vectors referenced (x in x.get(...) and in x.len())

View File

@ -1,6 +1,6 @@
use rustc::ty;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

View File

@ -1,7 +1,7 @@
use crate::utils::{match_type, method_chain_args, paths, snippet_with_applicability, span_lint_and_sugg};
use crate::utils::{is_type_diagnostic_item, method_chain_args, snippet_with_applicability, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{print, Expr, ExprKind, MatchSource, PatKind, QPath};
use rustc_hir::{Expr, ExprKind, MatchSource, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -45,8 +45,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet {
if let ExprKind::MethodCall(_, ok_span, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok()
if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation
if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT);
if print::to_string(print::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type;
if is_type_diagnostic_item(cx, cx.tables.expr_ty(&result_types[0]), sym!(result_type));
if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
then {
let mut applicability = Applicability::MachineApplicable;

View File

@ -1,9 +1,9 @@
//! lint on if branches that could be swapped so no `!` operation is necessary
//! on the condition
use rustc::lint::in_external_macro;
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use crate::utils::span_lint_and_help;

View File

@ -135,11 +135,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitReturn {
let def_id = cx.tcx.hir().body_owner_def_id(body.id());
// Building MIR for `fn`s with unsatisfiable preds results in ICE.
if fn_has_unsatisfiable_preds(cx, def_id) {
if fn_has_unsatisfiable_preds(cx, def_id.to_def_id()) {
return;
}
let mir = cx.tcx.optimized_mir(def_id);
let mir = cx.tcx.optimized_mir(def_id.to_def_id());
// checking return type through MIR, HIR is not able to determine inferred closure return types
// make sure it's not a macro

View File

@ -2,10 +2,10 @@
use crate::consts::{constant, Constant};
use crate::utils::{higher, span_lint, span_lint_and_help};
use rustc::ty;
use rustc_ast::ast::RangeLimits;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {

View File

@ -1,21 +1,24 @@
//! lint when there is a large size difference between variants on an enum
use crate::utils::{snippet_opt, span_lint_and_then};
use rustc::ty::layout::LayoutOf;
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind, VariantData};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_target::abi::LayoutOf;
declare_clippy_lint! {
/// **What it does:** Checks for large size differences between variants on
/// `enum`s.
///
/// **Why is this bad?** Enum size is bounded by the largest variant. Having a
/// large variant
/// can penalize the memory layout of that enum.
/// large variant can penalize the memory layout of that enum.
///
/// **Known problems:** None.
/// **Known problems:** This lint obviously cannot take the distribution of
/// variants in your running program into account. It is possible that the
/// smaller variants make up less than 1% of all instances, in which case
/// the overhead is negligible and the boxing is counter-productive. Always
/// measure the change this lint suggests.
///
/// **Example:**
/// ```rust
@ -52,8 +55,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant {
let ty = cx.tcx.type_of(did);
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;
let mut second_variant: Option<(_, _)> = None;
for (i, variant) in adt.variants.iter().enumerate() {
let size: u64 = variant
@ -69,12 +72,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant {
let grouped = (size, (i, variant));
update_if(&mut smallest_variant, grouped, |a, b| b.0 <= a.0);
update_if(&mut largest_variant, grouped, |a, b| b.0 >= a.0);
if grouped.0 >= largest_variant.map_or(0, |x| x.0) {
second_variant = largest_variant;
largest_variant = Some(grouped);
}
}
if let (Some(smallest), Some(largest)) = (smallest_variant, largest_variant) {
let difference = largest.0 - smallest.0;
if let (Some(largest), Some(second)) = (largest_variant, second_variant) {
let difference = largest.0 - second.0;
if difference > self.maximum_size_difference_allowed {
let (i, variant) = largest.1;
@ -114,16 +119,3 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LargeEnumVariant {
}
}
}
fn update_if<T, F>(old: &mut Option<T>, new: T, f: F)
where
F: Fn(&T, &T) -> bool,
{
if let Some(ref mut val) = *old {
if f(val, &new) {
*val = new;
}
} else {
*old = Some(new);
}
}

View File

@ -1,7 +1,7 @@
use rustc::mir::interpret::ConstValue;
use rustc::ty::{self, ConstKind};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::{self, ConstKind};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use if_chain::if_chain;

View File

@ -1,11 +1,11 @@
use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty};
use rustc::ty;
use rustc_ast::ast::{LitKind, Name};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::{AssocItemKind, BinOpKind, Expr, ExprKind, ImplItemRef, Item, ItemKind, TraitItemRef};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::{Span, Spanned};
@ -121,7 +121,7 @@ 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.as_str() == name
&& if let AssocItemKind::Method { has_self } = item.kind {
&& if let AssocItemKind::Fn { has_self } = item.kind {
has_self && {
let did = cx.tcx.hir().local_def_id(item.id.hir_id);
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
@ -149,8 +149,8 @@ fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item<'_>, trait_i
.iter()
.flat_map(|&i| cx.tcx.associated_items(i).in_definition_order())
.any(|i| {
i.kind == ty::AssocKind::Method
&& i.method_has_self_argument
i.kind == ty::AssocKind::Fn
&& i.fn_has_self_parameter
&& i.ident.name == sym!(is_empty)
&& cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
});
@ -172,7 +172,7 @@ fn check_trait_items(cx: &LateContext<'_, '_>, visited_trait: &Item<'_>, trait_i
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.as_str() == name
&& if let AssocItemKind::Method { has_self } = item.kind {
&& if let AssocItemKind::Fn { has_self } = item.kind {
has_self && {
let did = cx.tcx.hir().local_def_id(item.id.hir_id);
cx.tcx.fn_sig(did).inputs().skip_binder().len() == 1
@ -261,7 +261,7 @@ fn check_len(
fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
/// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssocItem) -> bool {
if let ty::AssocKind::Method = item.kind {
if let ty::AssocKind::Fn = item.kind {
if item.ident.name.as_str() == "is_empty" {
let sig = cx.tcx.fn_sig(item.def_id);
let ty = sig.skip_binder();

View File

@ -1,12 +1,12 @@
use crate::utils::{higher, qpath_res, snippet, span_lint_and_then};
use if_chain::if_chain;
use rustc::hir::map::Map;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::intravisit;
use rustc_hir::BindingAnnotation;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {

View File

@ -1,7 +1,8 @@
use if_chain::if_chain;
use rustc::lint::in_external_macro;
use rustc_hir::{PatKind, Stmt, StmtKind};
use rustc_hir::{Local, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use crate::utils::{is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help};
@ -66,22 +67,28 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [
];
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore {
fn check_stmt(&mut self, cx: &LateContext<'_, '_>, stmt: &Stmt<'_>) {
if in_external_macro(cx.tcx.sess, stmt.span) {
fn check_local(&mut self, cx: &LateContext<'_, '_>, local: &Local<'_>) {
if in_external_macro(cx.tcx.sess, local.span) {
return;
}
if_chain! {
if let StmtKind::Local(ref local) = stmt.kind;
if let PatKind::Wild = local.pat.kind;
if let Some(ref init) = local.init;
then {
let check_ty = |ty| SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, ty, path));
if cx.tables.expr_ty(init).walk().any(check_ty) {
let init_ty = cx.tables.expr_ty(init);
let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
GenericArgKind::Type(inner_ty) => {
SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
},
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
});
if contains_sync_guard {
span_lint_and_help(
cx,
LET_UNDERSCORE_LOCK,
stmt.span,
local.span,
"non-binding let on a synchronization lock",
"consider using an underscore-prefixed named \
binding or dropping explicitly with `std::mem::drop`"
@ -90,7 +97,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore {
span_lint_and_help(
cx,
LET_UNDERSCORE_MUST_USE,
stmt.span,
local.span,
"non-binding let on an expression with `#[must_use]` type",
"consider explicitly using expression value"
)
@ -98,7 +105,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetUnderscore {
span_lint_and_help(
cx,
LET_UNDERSCORE_MUST_USE,
stmt.span,
local.span,
"non-binding let on a result of a `#[must_use]` function",
"consider explicitly using function result"
)

View File

@ -18,8 +18,6 @@
#[allow(unused_extern_crates)]
extern crate fmt_macros;
#[allow(unused_extern_crates)]
extern crate rustc;
#[allow(unused_extern_crates)]
extern crate rustc_ast;
#[allow(unused_extern_crates)]
extern crate rustc_ast_pretty;
@ -34,6 +32,8 @@ extern crate rustc_errors;
#[allow(unused_extern_crates)]
extern crate rustc_hir;
#[allow(unused_extern_crates)]
extern crate rustc_hir_pretty;
#[allow(unused_extern_crates)]
extern crate rustc_index;
#[allow(unused_extern_crates)]
extern crate rustc_infer;
@ -42,6 +42,8 @@ extern crate rustc_lexer;
#[allow(unused_extern_crates)]
extern crate rustc_lint;
#[allow(unused_extern_crates)]
extern crate rustc_middle;
#[allow(unused_extern_crates)]
extern crate rustc_mir;
#[allow(unused_extern_crates)]
extern crate rustc_parse;
@ -80,7 +82,7 @@ use rustc_session::Session;
/// ```
/// # #![feature(rustc_private)]
/// # #[allow(unused_extern_crates)]
/// # extern crate rustc;
/// # extern crate rustc_middle;
/// # #[allow(unused_extern_crates)]
/// # extern crate rustc_session;
/// # #[macro_use]
@ -168,157 +170,157 @@ mod consts;
mod utils;
// begin lints modules, do not remove this comment, its used in `update_lints`
pub mod approx_const;
pub mod arithmetic;
pub mod as_conversions;
pub mod assertions_on_constants;
pub mod assign_ops;
pub mod atomic_ordering;
pub mod attrs;
pub mod bit_mask;
pub mod blacklisted_name;
pub mod block_in_if_condition;
pub mod booleans;
pub mod bytecount;
pub mod cargo_common_metadata;
pub mod checked_conversions;
pub mod cognitive_complexity;
pub mod collapsible_if;
pub mod comparison_chain;
pub mod copies;
pub mod copy_iterator;
pub mod dbg_macro;
pub mod default_trait_access;
pub mod derive;
pub mod doc;
pub mod double_comparison;
pub mod double_parens;
pub mod drop_bounds;
pub mod drop_forget_ref;
pub mod duration_subsec;
pub mod else_if_without_else;
pub mod empty_enum;
pub mod entry;
pub mod enum_clike;
pub mod enum_variants;
pub mod eq_op;
pub mod erasing_op;
pub mod escape;
pub mod eta_reduction;
pub mod eval_order_dependence;
pub mod excessive_bools;
pub mod exit;
pub mod explicit_write;
pub mod fallible_impl_from;
pub mod float_literal;
pub mod floating_point_arithmetic;
pub mod format;
pub mod formatting;
pub mod functions;
pub mod get_last_with_len;
pub mod identity_conversion;
pub mod identity_op;
pub mod if_let_some_result;
pub mod if_not_else;
pub mod implicit_return;
pub mod indexing_slicing;
pub mod infinite_iter;
pub mod inherent_impl;
pub mod inherent_to_string;
pub mod inline_fn_without_body;
pub mod int_plus_one;
pub mod integer_division;
pub mod items_after_statements;
pub mod large_enum_variant;
pub mod large_stack_arrays;
pub mod len_zero;
pub mod let_if_seq;
pub mod let_underscore;
pub mod lifetimes;
pub mod literal_representation;
pub mod loops;
pub mod macro_use;
pub mod main_recursion;
pub mod map_clone;
pub mod map_unit_fn;
pub mod matches;
pub mod mem_discriminant;
pub mod mem_forget;
pub mod mem_replace;
pub mod methods;
pub mod minmax;
pub mod misc;
pub mod misc_early;
pub mod missing_const_for_fn;
pub mod missing_doc;
pub mod missing_inline;
pub mod modulo_arithmetic;
pub mod multiple_crate_versions;
pub mod mut_key;
pub mod mut_mut;
pub mod mut_reference;
pub mod mutable_debug_assertion;
pub mod mutex_atomic;
pub mod needless_bool;
pub mod needless_borrow;
pub mod needless_borrowed_ref;
pub mod needless_continue;
pub mod needless_pass_by_value;
pub mod needless_update;
pub mod neg_cmp_op_on_partial_ord;
pub mod neg_multiply;
pub mod new_without_default;
pub mod no_effect;
pub mod non_copy_const;
pub mod non_expressive_names;
pub mod open_options;
pub mod option_env_unwrap;
pub mod overflow_check_conditional;
pub mod panic_unimplemented;
pub mod partialeq_ne_impl;
pub mod path_buf_push_overwrite;
pub mod precedence;
pub mod ptr;
pub mod ptr_offset_with_cast;
pub mod question_mark;
pub mod ranges;
pub mod redundant_clone;
pub mod redundant_field_names;
pub mod redundant_pattern_matching;
pub mod redundant_pub_crate;
pub mod redundant_static_lifetimes;
pub mod reference;
pub mod regex;
pub mod replace_consts;
pub mod returns;
pub mod serde_api;
pub mod shadow;
pub mod single_component_path_imports;
pub mod slow_vector_initialization;
pub mod strings;
pub mod suspicious_trait_impl;
pub mod swap;
pub mod tabs_in_doc_comments;
pub mod temporary_assignment;
pub mod to_digit_is_some;
pub mod trait_bounds;
pub mod transmute;
pub mod transmuting_null;
pub mod trivially_copy_pass_by_ref;
pub mod try_err;
pub mod types;
pub mod unicode;
pub mod unsafe_removed_from_name;
pub mod unused_io_amount;
pub mod unused_self;
pub mod unwrap;
pub mod use_self;
pub mod vec;
pub mod verbose_file_reads;
pub mod wildcard_dependencies;
pub mod wildcard_imports;
pub mod write;
pub mod zero_div_zero;
mod approx_const;
mod arithmetic;
mod as_conversions;
mod assertions_on_constants;
mod assign_ops;
mod atomic_ordering;
mod attrs;
mod bit_mask;
mod blacklisted_name;
mod block_in_if_condition;
mod booleans;
mod bytecount;
mod cargo_common_metadata;
mod checked_conversions;
mod cognitive_complexity;
mod collapsible_if;
mod comparison_chain;
mod copies;
mod copy_iterator;
mod dbg_macro;
mod default_trait_access;
mod derive;
mod doc;
mod double_comparison;
mod double_parens;
mod drop_bounds;
mod drop_forget_ref;
mod duration_subsec;
mod else_if_without_else;
mod empty_enum;
mod entry;
mod enum_clike;
mod enum_variants;
mod eq_op;
mod erasing_op;
mod escape;
mod eta_reduction;
mod eval_order_dependence;
mod excessive_bools;
mod exit;
mod explicit_write;
mod fallible_impl_from;
mod float_literal;
mod floating_point_arithmetic;
mod format;
mod formatting;
mod functions;
mod get_last_with_len;
mod identity_conversion;
mod identity_op;
mod if_let_some_result;
mod if_not_else;
mod implicit_return;
mod indexing_slicing;
mod infinite_iter;
mod inherent_impl;
mod inherent_to_string;
mod inline_fn_without_body;
mod int_plus_one;
mod integer_division;
mod items_after_statements;
mod large_enum_variant;
mod large_stack_arrays;
mod len_zero;
mod let_if_seq;
mod let_underscore;
mod lifetimes;
mod literal_representation;
mod loops;
mod macro_use;
mod main_recursion;
mod map_clone;
mod map_unit_fn;
mod matches;
mod mem_discriminant;
mod mem_forget;
mod mem_replace;
mod methods;
mod minmax;
mod misc;
mod misc_early;
mod missing_const_for_fn;
mod missing_doc;
mod missing_inline;
mod modulo_arithmetic;
mod multiple_crate_versions;
mod mut_key;
mod mut_mut;
mod mut_reference;
mod mutable_debug_assertion;
mod mutex_atomic;
mod needless_bool;
mod needless_borrow;
mod needless_borrowed_ref;
mod needless_continue;
mod needless_pass_by_value;
mod needless_update;
mod neg_cmp_op_on_partial_ord;
mod neg_multiply;
mod new_without_default;
mod no_effect;
mod non_copy_const;
mod non_expressive_names;
mod open_options;
mod option_env_unwrap;
mod overflow_check_conditional;
mod panic_unimplemented;
mod partialeq_ne_impl;
mod path_buf_push_overwrite;
mod precedence;
mod ptr;
mod ptr_offset_with_cast;
mod question_mark;
mod ranges;
mod redundant_clone;
mod redundant_field_names;
mod redundant_pattern_matching;
mod redundant_pub_crate;
mod redundant_static_lifetimes;
mod reference;
mod regex;
mod returns;
mod serde_api;
mod shadow;
mod single_component_path_imports;
mod slow_vector_initialization;
mod strings;
mod suspicious_trait_impl;
mod swap;
mod tabs_in_doc_comments;
mod temporary_assignment;
mod to_digit_is_some;
mod trait_bounds;
mod transmute;
mod transmuting_null;
mod trivially_copy_pass_by_ref;
mod try_err;
mod types;
mod unicode;
mod unnamed_address;
mod unsafe_removed_from_name;
mod unused_io_amount;
mod unused_self;
mod unwrap;
mod use_self;
mod vec;
mod verbose_file_reads;
mod wildcard_dependencies;
mod wildcard_imports;
mod write;
mod zero_div_zero;
// end lints modules, do not remove this comment, its used in `update_lints`
pub use crate::utils::conf::Conf;
@ -468,6 +470,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
"clippy::unused_label",
"this lint has been uplifted to rustc and is now called `unused_labels`",
);
store.register_removed(
"clippy::replace_consts",
"associated-constants `MIN`/`MAX` of integers are prefer to `{min,max}_value()` and module constants",
);
// end deprecated lints, do not remove this comment, its used in `update_lints`
// begin register lints, do not remove this comment, its used in `update_lints`
@ -660,6 +666,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&methods::OPTION_UNWRAP_USED,
&methods::OR_FUN_CALL,
&methods::RESULT_EXPECT_USED,
&methods::RESULT_MAP_OR_INTO_OPTION,
&methods::RESULT_MAP_UNWRAP_OR_ELSE,
&methods::RESULT_UNWRAP_USED,
&methods::SEARCH_IS_SOME,
@ -753,7 +760,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&regex::INVALID_REGEX,
&regex::REGEX_MACRO,
&regex::TRIVIAL_REGEX,
&replace_consts::REPLACE_CONSTS,
&returns::LET_AND_RETURN,
&returns::NEEDLESS_RETURN,
&returns::UNUSED_UNIT,
@ -806,6 +812,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&types::LET_UNIT_VALUE,
&types::LINKEDLIST,
&types::OPTION_OPTION,
&types::REDUNDANT_ALLOCATION,
&types::TYPE_COMPLEXITY,
&types::UNIT_ARG,
&types::UNIT_CMP,
@ -814,12 +821,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&unicode::NON_ASCII_LITERAL,
&unicode::UNICODE_NOT_NFC,
&unicode::ZERO_WIDTH_SPACE,
&unnamed_address::FN_ADDRESS_COMPARISONS,
&unnamed_address::VTABLE_ADDRESS_COMPARISONS,
&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
&unused_io_amount::UNUSED_IO_AMOUNT,
&unused_self::UNUSED_SELF,
&unwrap::PANICKING_UNWRAP,
&unwrap::UNNECESSARY_UNWRAP,
&use_self::USE_SELF,
&utils::internal_lints::CLIPPY_LINTS_INTERNAL,
&utils::internal_lints::COMPILER_LINT_FUNCTIONS,
&utils::internal_lints::DEFAULT_LINT,
&utils::internal_lints::LINT_WITHOUT_LINT_PASS,
&utils::internal_lints::OUTER_EXPN_EXPN_DATA,
&utils::internal_lints::PRODUCE_ICE,
&vec::USELESS_VEC,
&verbose_file_reads::VERBOSE_FILE_READS,
&wildcard_dependencies::WILDCARD_DEPENDENCIES,
@ -951,7 +966,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|| box identity_conversion::IdentityConversion::default());
store.register_late_pass(|| box types::ImplicitHasher);
store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
store.register_late_pass(|| box replace_consts::ReplaceConsts);
store.register_late_pass(|| box types::UnitArg);
store.register_late_pass(|| box double_comparison::DoubleComparisons);
store.register_late_pass(|| box question_mark::QuestionMark);
@ -1024,6 +1038,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_early_pass(|| box macro_use::MacroUseImports);
store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
store.register_late_pass(|| box unnamed_address::UnnamedAddress);
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@ -1062,6 +1077,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&shadow::SHADOW_REUSE),
LintId::of(&shadow::SHADOW_SAME),
LintId::of(&strings::STRING_ADD),
LintId::of(&verbose_file_reads::VERBOSE_FILE_READS),
LintId::of(&write::PRINT_STDOUT),
LintId::of(&write::USE_DEBUG),
]);
@ -1089,6 +1105,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS),
LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS),
LintId::of(&literal_representation::LARGE_DIGIT_GROUPS),
LintId::of(&literal_representation::UNREADABLE_LITERAL),
LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
LintId::of(&loops::EXPLICIT_ITER_LOOP),
LintId::of(&macro_use::MACRO_USE_IMPORTS),
@ -1096,6 +1113,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&methods::FILTER_MAP),
LintId::of(&methods::FILTER_MAP_NEXT),
LintId::of(&methods::FIND_MAP),
LintId::of(&methods::INEFFICIENT_TO_STRING),
LintId::of(&methods::MAP_FLATTEN),
LintId::of(&methods::OPTION_MAP_UNWRAP_OR),
LintId::of(&methods::OPTION_MAP_UNWRAP_OR_ELSE),
@ -1107,17 +1125,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
LintId::of(&non_expressive_names::SIMILAR_NAMES),
LintId::of(&ranges::RANGE_PLUS_ONE),
LintId::of(&replace_consts::REPLACE_CONSTS),
LintId::of(&shadow::SHADOW_UNRELATED),
LintId::of(&strings::STRING_ADD_ASSIGN),
LintId::of(&trait_bounds::TYPE_REPETITION_IN_BOUNDS),
LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF),
LintId::of(&types::CAST_LOSSLESS),
LintId::of(&types::CAST_POSSIBLE_TRUNCATION),
LintId::of(&types::CAST_POSSIBLE_WRAP),
LintId::of(&types::CAST_PRECISION_LOSS),
LintId::of(&types::CAST_SIGN_LOSS),
LintId::of(&types::IMPLICIT_HASHER),
LintId::of(&types::INVALID_UPCAST_COMPARISONS),
LintId::of(&types::LET_UNIT_VALUE),
LintId::of(&types::LINKEDLIST),
LintId::of(&types::OPTION_OPTION),
LintId::of(&unicode::NON_ASCII_LITERAL),
LintId::of(&unicode::UNICODE_NOT_NFC),
LintId::of(&unused_self::UNUSED_SELF),
@ -1153,7 +1174,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&booleans::LOGIC_BUG),
LintId::of(&booleans::NONMINIMAL_BOOL),
LintId::of(&bytecount::NAIVE_BYTECOUNT),
LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY),
LintId::of(&collapsible_if::COLLAPSIBLE_IF),
LintId::of(&comparison_chain::COMPARISON_CHAIN),
LintId::of(&copies::IFS_SAME_COND),
@ -1210,7 +1230,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&lifetimes::NEEDLESS_LIFETIMES),
LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING),
LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES),
LintId::of(&literal_representation::UNREADABLE_LITERAL),
LintId::of(&loops::EMPTY_LOOP),
LintId::of(&loops::EXPLICIT_COUNTER_LOOP),
LintId::of(&loops::FOR_KV_MAP),
@ -1250,7 +1269,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&methods::EXPECT_FUN_CALL),
LintId::of(&methods::FILTER_NEXT),
LintId::of(&methods::FLAT_MAP_IDENTITY),
LintId::of(&methods::INEFFICIENT_TO_STRING),
LintId::of(&methods::INTO_ITER_ON_REF),
LintId::of(&methods::ITERATOR_STEP_BY_ZERO),
LintId::of(&methods::ITER_CLONED_COLLECT),
@ -1264,6 +1282,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&methods::OPTION_AS_REF_DEREF),
LintId::of(&methods::OPTION_MAP_OR_NONE),
LintId::of(&methods::OR_FUN_CALL),
LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION),
LintId::of(&methods::SEARCH_IS_SOME),
LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT),
LintId::of(&methods::SINGLE_CHAR_PATTERN),
@ -1356,7 +1375,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&transmute::UNSOUND_COLLECTION_TRANSMUTE),
LintId::of(&transmute::WRONG_TRANSMUTE),
LintId::of(&transmuting_null::TRANSMUTING_NULL),
LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF),
LintId::of(&try_err::TRY_ERR),
LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
LintId::of(&types::BORROWED_BOX),
@ -1366,21 +1384,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&types::CHAR_LIT_AS_U8),
LintId::of(&types::FN_TO_NUMERIC_CAST),
LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
LintId::of(&types::IMPLICIT_HASHER),
LintId::of(&types::LET_UNIT_VALUE),
LintId::of(&types::OPTION_OPTION),
LintId::of(&types::REDUNDANT_ALLOCATION),
LintId::of(&types::TYPE_COMPLEXITY),
LintId::of(&types::UNIT_ARG),
LintId::of(&types::UNIT_CMP),
LintId::of(&types::UNNECESSARY_CAST),
LintId::of(&types::VEC_BOX),
LintId::of(&unicode::ZERO_WIDTH_SPACE),
LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
LintId::of(&unwrap::PANICKING_UNWRAP),
LintId::of(&unwrap::UNNECESSARY_UNWRAP),
LintId::of(&vec::USELESS_VEC),
LintId::of(&verbose_file_reads::VERBOSE_FILE_READS),
LintId::of(&write::PRINTLN_EMPTY_STRING),
LintId::of(&write::PRINT_LITERAL),
LintId::of(&write::PRINT_WITH_NEWLINE),
@ -1418,7 +1435,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&len_zero::LEN_ZERO),
LintId::of(&let_if_seq::USELESS_LET_IF_SEQ),
LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING),
LintId::of(&literal_representation::UNREADABLE_LITERAL),
LintId::of(&loops::EMPTY_LOOP),
LintId::of(&loops::FOR_KV_MAP),
LintId::of(&loops::NEEDLESS_RANGE_LOOP),
@ -1443,6 +1459,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&methods::NEW_RET_NO_SELF),
LintId::of(&methods::OK_EXPECT),
LintId::of(&methods::OPTION_MAP_OR_NONE),
LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION),
LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT),
LintId::of(&methods::STRING_EXTEND_CHARS),
LintId::of(&methods::UNNECESSARY_FOLD),
@ -1478,8 +1495,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&try_err::TRY_ERR),
LintId::of(&types::FN_TO_NUMERIC_CAST),
LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
LintId::of(&types::IMPLICIT_HASHER),
LintId::of(&types::LET_UNIT_VALUE),
LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
LintId::of(&write::PRINTLN_EMPTY_STRING),
LintId::of(&write::PRINT_LITERAL),
@ -1493,7 +1508,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP),
LintId::of(&attrs::DEPRECATED_CFG_ATTR),
LintId::of(&booleans::NONMINIMAL_BOOL),
LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY),
LintId::of(&double_comparison::DOUBLE_COMPARISONS),
LintId::of(&double_parens::DOUBLE_PARENS),
LintId::of(&duration_subsec::DURATION_SUBSEC),
@ -1557,13 +1571,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&transmute::TRANSMUTE_PTR_TO_REF),
LintId::of(&types::BORROWED_BOX),
LintId::of(&types::CHAR_LIT_AS_U8),
LintId::of(&types::OPTION_OPTION),
LintId::of(&types::TYPE_COMPLEXITY),
LintId::of(&types::UNIT_ARG),
LintId::of(&types::UNNECESSARY_CAST),
LintId::of(&types::VEC_BOX),
LintId::of(&unwrap::UNNECESSARY_UNWRAP),
LintId::of(&verbose_file_reads::VERBOSE_FILE_READS),
LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
]);
@ -1630,6 +1642,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&types::CAST_REF_TO_MUT),
LintId::of(&types::UNIT_CMP),
LintId::of(&unicode::ZERO_WIDTH_SPACE),
LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
LintId::of(&unwrap::PANICKING_UNWRAP),
]);
@ -1642,7 +1656,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&loops::MANUAL_MEMCPY),
LintId::of(&loops::NEEDLESS_COLLECT),
LintId::of(&methods::EXPECT_FUN_CALL),
LintId::of(&methods::INEFFICIENT_TO_STRING),
LintId::of(&methods::ITER_NTH),
LintId::of(&methods::OR_FUN_CALL),
LintId::of(&methods::SINGLE_CHAR_PATTERN),
@ -1650,8 +1663,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&mutex_atomic::MUTEX_ATOMIC),
LintId::of(&redundant_clone::REDUNDANT_CLONE),
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
LintId::of(&trivially_copy_pass_by_ref::TRIVIALLY_COPY_PASS_BY_REF),
LintId::of(&types::BOX_VEC),
LintId::of(&types::REDUNDANT_ALLOCATION),
LintId::of(&vec::USELESS_VEC),
]);
@ -1663,6 +1676,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY),
LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM),
LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS),
LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS),

View File

@ -1,5 +1,3 @@
use rustc::hir::map::Map;
use rustc::lint::in_external_macro;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{
@ -11,13 +9,14 @@ use rustc_hir::{
ItemKind, Lifetime, LifetimeName, ParamName, QPath, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty,
TyKind, WhereClause, WherePredicate,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::symbol::kw;
use crate::reexport::Name;
use crate::utils::{last_path_segment, span_lint, trait_ref_of_method};
use crate::utils::{in_macro, last_path_segment, span_lint, trait_ref_of_method};
declare_clippy_lint! {
/// **What it does:** Checks for lifetime annotations which can be removed by
@ -125,7 +124,7 @@ fn check_fn_inner<'a, 'tcx>(
span: Span,
report_extra_lifetimes: bool,
) {
if in_external_macro(cx.sess(), span) || has_where_lifetimes(cx, &generics.where_clause) {
if in_macro(span) || has_where_lifetimes(cx, &generics.where_clause) {
return;
}

View File

@ -7,10 +7,10 @@ use crate::utils::{
snippet_opt, span_lint_and_sugg,
};
use if_chain::if_chain;
use rustc::lint::in_external_macro;
use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
declare_clippy_lint! {
@ -27,7 +27,7 @@ declare_clippy_lint! {
/// let x: u64 = 61864918973511;
/// ```
pub UNREADABLE_LITERAL,
style,
pedantic,
"long integer literal without underscores"
}
@ -186,6 +186,9 @@ impl EarlyLintPass for LiteralDigitGrouping {
}
}
// Length of each UUID hyphenated group in hex digits.
const UUID_GROUP_LENS: [usize; 5] = [8, 4, 4, 4, 12];
impl LiteralDigitGrouping {
fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
if_chain! {
@ -196,6 +199,10 @@ impl LiteralDigitGrouping {
return;
}
if Self::is_literal_uuid_formatted(&mut num_lit) {
return;
}
let result = (|| {
let integral_group_size = Self::get_group_size(num_lit.integer.split('_'))?;
@ -266,6 +273,28 @@ impl LiteralDigitGrouping {
}
}
/// Checks whether the numeric literal matches the formatting of a UUID.
///
/// Returns `true` if the radix is hexadecimal, and the groups match the
/// UUID format of 8-4-4-4-12.
fn is_literal_uuid_formatted(num_lit: &mut NumericLiteral<'_>) -> bool {
if num_lit.radix != Radix::Hexadecimal {
return false;
}
// UUIDs should not have a fraction
if num_lit.fraction.is_some() {
return false;
}
let group_sizes: Vec<usize> = num_lit.integer.split('_').map(str::len).collect();
if UUID_GROUP_LENS.len() == group_sizes.len() {
UUID_GROUP_LENS.iter().zip(&group_sizes).all(|(&a, &b)| a == b)
} else {
false
}
}
/// Given the sizes of the digit groups of both integral and fractional
/// parts, and the length
/// of both parts, determine if the digits have been grouped consistently.

View File

@ -11,10 +11,6 @@ use crate::utils::{
use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sext, sugg};
use if_chain::if_chain;
use itertools::Itertools;
use rustc::hir::map::Map;
use rustc::lint::in_external_macro;
use rustc::middle::region;
use rustc::ty::{self, Ty};
use rustc_ast::ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
@ -26,9 +22,13 @@ use rustc_hir::{
};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::lint::in_external_macro;
use rustc_middle::middle::region;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::{BytePos, Symbol};
use rustc_span::BytePos;
use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase};
use std::iter::{once, Iterator};
use std::mem;
@ -654,7 +654,7 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
let stmts = block.stmts.iter().map(stmt_to_expr);
let expr = once(block.expr.as_ref().map(|p| &**p));
let expr = once(block.expr.as_deref());
let mut iter = stmts.chain(expr).filter_map(|e| e);
never_loop_expr_seq(&mut iter, main_loop_id)
}
@ -662,7 +662,7 @@ fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> {
match stmt.kind {
StmtKind::Semi(ref e, ..) | StmtKind::Expr(ref e, ..) => Some(e),
StmtKind::Local(ref local) => local.init.as_ref().map(|p| &**p),
StmtKind::Local(ref local) => local.init.as_deref(),
_ => None,
}
}
@ -720,7 +720,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
ExprKind::Struct(_, _, None)
| ExprKind::Yield(_, _)
| ExprKind::Closure(_, _, _, _, _)
| ExprKind::InlineAsm(_)
| ExprKind::LlvmInlineAsm(_)
| ExprKind::Path(_)
| ExprKind::Lit(_)
| ExprKind::Err => NeverLoopResult::Otherwise,
@ -804,7 +804,7 @@ fn is_slice_like<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'_>) -> bool {
_ => false,
};
is_slice || is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type")) || match_type(cx, ty, &paths::VEC_DEQUE)
is_slice || is_type_diagnostic_item(cx, ty, sym!(vec_type)) || match_type(cx, ty, &paths::VEC_DEQUE)
}
fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>, var: HirId) -> Option<FixedOffsetVar> {
@ -922,7 +922,7 @@ fn get_indexed_assignments<'a, 'tcx>(
.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![])
.unwrap_or_default()
} else {
get_assignment(cx, body, var).into_iter().collect()
}
@ -1392,7 +1392,7 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>, e
/// Checks for `for` loops over `Option`s and `Result`s.
fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>) {
let ty = cx.tables.expr_ty(arg);
if match_type(cx, ty, &paths::OPTION) {
if is_type_diagnostic_item(cx, ty, sym!(option_type)) {
span_lint_and_help(
cx,
FOR_LOOP_OVER_OPTION,
@ -1408,7 +1408,7 @@ fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>) {
snippet(cx, arg.span, "_")
),
);
} else if match_type(cx, ty, &paths::RESULT) {
} else if is_type_diagnostic_item(cx, ty, sym!(result_type)) {
span_lint_and_help(
cx,
FOR_LOOP_OVER_RESULT,
@ -1955,7 +1955,7 @@ fn is_ref_iterable_type(cx: &LateContext<'_, '_>, e: &Expr<'_>) -> bool {
// will allow further borrows afterwards
let ty = cx.tables.expr_ty(e);
is_iterable_array(ty, cx) ||
is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type")) ||
is_type_diagnostic_item(cx, ty, sym!(vec_type)) ||
match_type(cx, ty, &paths::LINKED_LIST) ||
match_type(cx, ty, &paths::HASHMAP) ||
match_type(cx, ty, &paths::HASHSET) ||
@ -2465,7 +2465,7 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, '
if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
then {
let ty = cx.tables.node_type(ty.hir_id);
if is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type")) ||
if is_type_diagnostic_item(cx, ty, sym!(vec_type)) ||
match_type(cx, ty, &paths::VEC_DEQUE) ||
match_type(cx, ty, &paths::BTREEMAP) ||
match_type(cx, ty, &paths::HASHMAP) {

View File

@ -1,13 +1,13 @@
use crate::utils::paths;
use crate::utils::{
is_copy, match_trait_method, match_type, remove_blocks, snippet_with_applicability, span_lint_and_sugg,
is_copy, is_type_diagnostic_item, match_trait_method, remove_blocks, snippet_with_applicability, span_lint_and_sugg,
};
use if_chain::if_chain;
use rustc::ty;
use rustc_ast::ast::Ident;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
@ -52,7 +52,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MapClone {
if args.len() == 2;
if method.ident.as_str() == "map";
let ty = cx.tables.expr_ty(&args[0]);
if match_type(cx, ty, &paths::OPTION) || match_trait_method(cx, e, &paths::ITERATOR);
if is_type_diagnostic_item(cx, ty, sym!(option_type)) || match_trait_method(cx, e, &paths::ITERATOR);
if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind;
let closure_body = cx.tcx.hir().body(body_id);
let closure_expr = remove_blocks(&closure_body.value);

View File

@ -1,10 +1,9 @@
use crate::utils::paths;
use crate::utils::{iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then};
use crate::utils::{is_type_diagnostic_item, iter_input_pats, method_chain_args, snippet, span_lint_and_then};
use if_chain::if_chain;
use rustc::ty::{self, Ty};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
@ -206,9 +205,9 @@ fn suggestion_msg(function_type: &str, map_type: &str) -> String {
fn lint_map_unit_fn(cx: &LateContext<'_, '_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) {
let var_arg = &map_args[0];
let (map_type, variant, lint) = if match_type(cx, cx.tables.expr_ty(var_arg), &paths::OPTION) {
let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.tables.expr_ty(var_arg), sym!(option_type)) {
("Option", "Some", OPTION_MAP_UNIT_FN)
} else if match_type(cx, cx.tables.expr_ty(var_arg), &paths::RESULT) {
} else if is_type_diagnostic_item(cx, cx.tables.expr_ty(var_arg), sym!(result_type)) {
("Result", "Ok", RESULT_MAP_UNIT_FN)
} else {
return;

View File

@ -3,22 +3,22 @@ use crate::utils::paths;
use crate::utils::sugg::Sugg;
use crate::utils::usage::is_unused;
use crate::utils::{
expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, is_wild,
match_qpath, match_type, match_var, multispan_sugg, remove_blocks, snippet, snippet_block,
snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
walk_ptrs_ty,
expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable,
is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, multispan_sugg, remove_blocks, snippet,
snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
span_lint_and_then, walk_ptrs_ty,
};
use if_chain::if_chain;
use rustc::lint::in_external_macro;
use rustc::ty::{self, Ty};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::def::CtorKind;
use rustc_hir::{
print, Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Local, MatchSource, Mutability, Node, Pat,
PatKind, QPath, RangeEnd,
Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Local, MatchSource, Mutability, Node, Pat, PatKind,
QPath, RangeEnd,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use std::cmp::Ordering;
@ -447,6 +447,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
#[rustfmt::skip]
fn check_single_match(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
if in_macro(expr.span) {
// Don't lint match expressions present in
// macro_rules! block
return;
}
if let PatKind::Or(..) = arms[0].pat.kind {
// don't lint for or patterns for now, this makes
// the lint noisy in unnecessary situations
@ -536,10 +541,12 @@ fn check_single_match_opt_like(
if !inner.iter().all(is_wild) {
return;
}
print::to_string(print::NO_ANN, |s| s.print_qpath(path, false))
rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
},
PatKind::Binding(BindingAnnotation::Unannotated, .., ident, None) => ident.to_string(),
PatKind::Path(ref path) => print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)),
PatKind::Path(ref path) => {
rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
},
_ => return,
};
@ -635,10 +642,10 @@ fn check_overlapping_arms<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ex: &'tcx Expr<'
fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
let ex_ty = walk_ptrs_ty(cx.tables.expr_ty(ex));
if match_type(cx, ex_ty, &paths::RESULT) {
if is_type_diagnostic_item(cx, ex_ty, sym!(result_type)) {
for arm in arms {
if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind {
let path_str = print::to_string(print::NO_ANN, |s| s.print_qpath(path, false));
let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
if path_str == "Err" {
let mut matching_wild = inner.iter().any(is_wild);
let mut ident_bind_name = String::from("_");
@ -1190,3 +1197,40 @@ where
None
}
#[test]
fn test_overlapping() {
use rustc_span::source_map::DUMMY_SP;
let sp = |s, e| SpannedRange {
span: DUMMY_SP,
node: (s, e),
};
assert_eq!(None, overlapping::<u8>(&[]));
assert_eq!(None, overlapping(&[sp(1, Bound::Included(4))]));
assert_eq!(
None,
overlapping(&[sp(1, Bound::Included(4)), sp(5, Bound::Included(6))])
);
assert_eq!(
None,
overlapping(&[
sp(1, Bound::Included(4)),
sp(5, Bound::Included(6)),
sp(10, Bound::Included(11))
],)
);
assert_eq!(
Some((&sp(1, Bound::Included(4)), &sp(3, Bound::Included(6)))),
overlapping(&[sp(1, Bound::Included(4)), sp(3, Bound::Included(6))])
);
assert_eq!(
Some((&sp(5, Bound::Included(6)), &sp(6, Bound::Included(11)))),
overlapping(&[
sp(1, Bound::Included(4)),
sp(5, Bound::Included(6)),
sp(6, Bound::Included(11))
],)
);
}

View File

@ -3,12 +3,13 @@ use crate::utils::{
span_lint_and_sugg, span_lint_and_then,
};
use if_chain::if_chain;
use rustc::lint::in_external_macro;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::symbol::sym;
declare_clippy_lint! {
/// **What it does:** Checks for `mem::replace()` on an `Option` with
@ -141,7 +142,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr<'_>, expr_span
if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
if let Some(repl_def_id) = cx.tables.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
then {
if match_def_path(cx, repl_def_id, &paths::MEM_UNINITIALIZED) {
if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, repl_def_id) {
span_lint_and_help(
cx,
MEM_REPLACE_WITH_UNINIT,
@ -149,7 +150,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_, '_>, src: &Expr<'_>, expr_span
"replacing with `mem::uninitialized()`",
"consider using the `take_mut` crate instead",
);
} else if match_def_path(cx, repl_def_id, &paths::MEM_ZEROED) &&
} else if cx.tcx.is_diagnostic_item(sym::mem_zeroed, repl_def_id) &&
!cx.tables.expr_ty(src).is_primitive() {
span_lint_and_help(
cx,

View File

@ -1,10 +1,10 @@
use super::INEFFICIENT_TO_STRING;
use crate::utils::{match_def_path, paths, snippet_with_applicability, span_lint_and_then, walk_ptrs_ty_depth};
use if_chain::if_chain;
use rustc::ty::{self, Ty};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
/// Checks for the `INEFFICIENT_TO_STRING` lint
pub fn lint<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) {

View File

@ -8,17 +8,18 @@ use std::fmt;
use std::iter;
use if_chain::if_chain;
use rustc::hir::map::Map;
use rustc::lint::in_external_macro;
use rustc::ty::{self, Predicate, Ty};
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Predicate, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::symbol::{sym, Symbol, SymbolStr};
use rustc_span::symbol::{sym, SymbolStr};
use crate::consts::{constant, Constant};
use crate::utils::usage::mutated_variables;
@ -330,6 +331,32 @@ declare_clippy_lint! {
"using `Option.map_or(None, f)`, which is more succinctly expressed as `and_then(f)`"
}
declare_clippy_lint! {
/// **What it does:** Checks for usage of `_.map_or(None, Some)`.
///
/// **Why is this bad?** Readability, this can be written more concisely as
/// `_.ok()`.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// Bad:
/// ```rust
/// # let r: Result<u32, &str> = Ok(1);
/// assert_eq!(Some(1), r.map_or(None, Some));
/// ```
///
/// Good:
/// ```rust
/// # let r: Result<u32, &str> = Ok(1);
/// assert_eq!(Some(1), r.ok());
/// ```
pub RESULT_MAP_OR_INTO_OPTION,
style,
"using `Result.map_or(None, Some)`, which is more succinctly expressed as `ok()`"
}
declare_clippy_lint! {
/// **What it does:** Checks for usage of `_.and_then(|x| Some(y))`.
///
@ -698,12 +725,12 @@ declare_clippy_lint! {
/// ["foo", "bar"].iter().map(|&s| s.to_string());
/// ```
pub INEFFICIENT_TO_STRING,
perf,
pedantic,
"using `to_string` on `&&T` where `T: ToString`"
}
declare_clippy_lint! {
/// **What it does:** Checks for `new` not returning `Self`.
/// **What it does:** Checks for `new` not returning a type that contains `Self`.
///
/// **Why is this bad?** As a convention, `new` methods are used to make a new
/// instance of a type.
@ -720,9 +747,31 @@ declare_clippy_lint! {
/// }
/// }
/// ```
///
/// ```rust
/// # struct Foo;
/// # struct FooError;
/// impl Foo {
/// // Good. Return type contains `Self`
/// fn new() -> Result<Foo, FooError> {
/// # Ok(Foo)
/// }
/// }
/// ```
///
/// ```rust
/// # struct Foo;
/// struct Bar(Foo);
/// impl Foo {
/// // Bad. The type name must contain `Self`.
/// fn new() -> Bar {
/// # Bar(Foo)
/// }
/// }
/// ```
pub NEW_RET_NO_SELF,
style,
"not returning `Self` in a `new` method"
"not returning type containing `Self` in a `new` method"
}
declare_clippy_lint! {
@ -1137,8 +1186,8 @@ declare_clippy_lint! {
/// ```rust
/// # let y: u32 = 0;
/// # let x: u32 = 100;
/// let add = x.checked_add(y).unwrap_or(u32::max_value());
/// let sub = x.checked_sub(y).unwrap_or(u32::min_value());
/// let add = x.checked_add(y).unwrap_or(u32::MAX);
/// let sub = x.checked_sub(y).unwrap_or(u32::MIN);
/// ```
///
/// can be written using dedicated methods for saturating addition/subtraction as:
@ -1248,6 +1297,7 @@ declare_lint_pass!(Methods => [
OPTION_MAP_UNWRAP_OR,
OPTION_MAP_UNWRAP_OR_ELSE,
RESULT_MAP_UNWRAP_OR_ELSE,
RESULT_MAP_OR_INTO_OPTION,
OPTION_MAP_OR_NONE,
OPTION_AND_THEN_SOME,
OR_FUN_CALL,
@ -1289,7 +1339,7 @@ declare_lint_pass!(Methods => [
]);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
#[allow(clippy::cognitive_complexity, clippy::too_many_lines)]
#[allow(clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) {
if in_macro(expr.span) {
return;
@ -1407,7 +1457,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id);
let item = cx.tcx.hir().expect_item(parent);
let def_id = cx.tcx.hir().local_def_id(item.hir_id);
let ty = cx.tcx.type_of(def_id);
let self_ty = cx.tcx.type_of(def_id);
if_chain! {
if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind;
if let Some(first_arg) = iter_input_pats(&sig.decl, cx.tcx.hir().body(id)).next();
@ -1425,11 +1475,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
then {
if cx.access_levels.is_exported(impl_item.hir_id) {
// check missing trait implementations
for &(method_name, n_args, self_kind, out_type, trait_name) in &TRAIT_METHODS {
for &(method_name, n_args, fn_header, self_kind, out_type, trait_name) in &TRAIT_METHODS {
if name == method_name &&
sig.decl.inputs.len() == n_args &&
out_type.matches(cx, &sig.decl.output) &&
self_kind.matches(cx, ty, first_arg_ty) {
self_kind.matches(cx, self_ty, first_arg_ty) &&
fn_header_equals(*fn_header, sig.header) {
span_lint(cx, SHOULD_IMPLEMENT_TRAIT, impl_item.span, &format!(
"defining a method called `{}` on this type; consider implementing \
the `{}` trait or choosing a less ambiguous name", name, trait_name));
@ -1441,7 +1492,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
.iter()
.find(|(ref conv, _)| conv.check(&name))
{
if !self_kinds.iter().any(|k| k.matches(cx, ty, first_arg_ty)) {
if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) {
let lint = if item.vis.node.is_pub() {
WRONG_PUB_SELF_CONVENTION
} else {
@ -1471,8 +1522,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
if let hir::ImplItemKind::Fn(_, _) = impl_item.kind {
let ret_ty = return_ty(cx, impl_item.hir_id);
let contains_self_ty = |ty: Ty<'tcx>| {
ty.walk().any(|inner| match inner.unpack() {
GenericArgKind::Type(inner_ty) => same_tys(cx, self_ty, inner_ty),
GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
})
};
// walk the return type and check for Self (this does not check associated types)
if ret_ty.walk().any(|inner_type| same_tys(cx, ty, inner_type)) {
if contains_self_ty(ret_ty) {
return;
}
@ -1486,18 +1545,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
let associated_type = binder.skip_binder();
// walk the associated type and check for Self
for inner_type in associated_type.walk() {
if same_tys(cx, ty, inner_type) {
if contains_self_ty(associated_type) {
return;
}
}
},
(_, _) => {},
}
}
}
if name == "new" && !same_tys(cx, ret_ty, ty) {
if name == "new" && !same_tys(cx, ret_ty, self_ty) {
span_lint(
cx,
NEW_RET_NO_SELF,
@ -1801,9 +1858,9 @@ fn lint_expect_fun_call(
}
let receiver_type = cx.tables.expr_ty_adjusted(&args[0]);
let closure_args = if match_type(cx, receiver_type, &paths::OPTION) {
let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym!(option_type)) {
"||"
} else if match_type(cx, receiver_type, &paths::RESULT) {
} else if is_type_diagnostic_item(cx, receiver_type, sym!(result_type)) {
"|_|"
} else {
return;
@ -1912,9 +1969,10 @@ fn lint_clone_on_copy(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, arg: &hir:
match &cx.tcx.hir().get(parent) {
hir::Node::Expr(parent) => match parent.kind {
// &*x is a nop, &x.clone() is not
hir::ExprKind::AddrOf(..) |
hir::ExprKind::AddrOf(..) => return,
// (*x).func() is useless, x.clone().func() can work in case func borrows mutably
hir::ExprKind::MethodCall(..) => return,
hir::ExprKind::MethodCall(_, _, parent_args) if expr.hir_id == parent_args[0].hir_id => return,
_ => {},
},
hir::Node::Stmt(stmt) => {
@ -1962,9 +2020,9 @@ fn lint_clone_on_ref_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, arg: &h
let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(arg));
if let ty::Adt(_, subst) = obj_ty.kind {
let caller_type = if match_type(cx, obj_ty, &paths::RC) {
let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
"Rc"
} else if match_type(cx, obj_ty, &paths::ARC) {
} else if is_type_diagnostic_item(cx, obj_ty, sym::Arc) {
"Arc"
} else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) {
"Weak"
@ -2031,7 +2089,7 @@ fn lint_cstring_as_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, source: &
if_chain! {
let source_type = cx.tables.expr_ty(source);
if let ty::Adt(def, substs) = source_type.kind;
if match_def_path(cx, def.did, &paths::RESULT);
if cx.tcx.is_diagnostic_item(sym!(result_type), def.did);
if match_type(cx, substs.type_at(0), &paths::CSTRING);
then {
span_lint_and_then(
@ -2053,7 +2111,7 @@ fn lint_iter_cloned_collect<'a, 'tcx>(
iter_args: &'tcx [hir::Expr<'_>],
) {
if_chain! {
if is_type_diagnostic_item(cx, cx.tables.expr_ty(expr), Symbol::intern("vec_type"));
if is_type_diagnostic_item(cx, cx.tables.expr_ty(expr), sym!(vec_type));
if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0]));
if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite());
@ -2182,7 +2240,7 @@ fn lint_iter_nth<'a, 'tcx>(
let mut_str = if is_mut { "_mut" } else { "" };
let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.tables.expr_ty(&iter_args[0])).is_some() {
"slice"
} else if is_type_diagnostic_item(cx, cx.tables.expr_ty(&iter_args[0]), Symbol::intern("vec_type")) {
} else if is_type_diagnostic_item(cx, cx.tables.expr_ty(&iter_args[0]), sym!(vec_type)) {
"Vec"
} else if match_type(cx, cx.tables.expr_ty(&iter_args[0]), &paths::VEC_DEQUE) {
"VecDeque"
@ -2239,7 +2297,7 @@ fn lint_get_unwrap<'a, 'tcx>(
let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() {
needs_ref = get_args_str.parse::<usize>().is_ok();
"slice"
} else if is_type_diagnostic_item(cx, expr_ty, Symbol::intern("vec_type")) {
} else if is_type_diagnostic_item(cx, expr_ty, sym!(vec_type)) {
needs_ref = get_args_str.parse::<usize>().is_ok();
"Vec"
} else if match_type(cx, expr_ty, &paths::VEC_DEQUE) {
@ -2320,7 +2378,7 @@ fn derefs_to_slice<'a, 'tcx>(
match ty.kind {
ty::Slice(_) => true,
ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
ty::Adt(..) => is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type")),
ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym!(vec_type)),
ty::Array(_, size) => {
if let Some(size) = size.try_eval_usize(cx.tcx, cx.param_env) {
size < 32
@ -2359,9 +2417,9 @@ fn derefs_to_slice<'a, 'tcx>(
fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) {
let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&unwrap_args[0]));
let mess = if match_type(cx, obj_ty, &paths::OPTION) {
let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
Some((OPTION_UNWRAP_USED, "an Option", "None"))
} else if match_type(cx, obj_ty, &paths::RESULT) {
} else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) {
Some((RESULT_UNWRAP_USED, "a Result", "Err"))
} else {
None
@ -2386,9 +2444,9 @@ fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, unwrap_args: &[hi
fn lint_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&expect_args[0]));
let mess = if match_type(cx, obj_ty, &paths::OPTION) {
let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
Some((OPTION_EXPECT_USED, "an Option", "None"))
} else if match_type(cx, obj_ty, &paths::RESULT) {
} else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) {
Some((RESULT_EXPECT_USED, "a Result", "Err"))
} else {
None
@ -2409,7 +2467,7 @@ fn lint_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, expect_args: &[hi
fn lint_ok_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) {
if_chain! {
// lint if the caller of `ok()` is a `Result`
if match_type(cx, cx.tables.expr_ty(&ok_args[0]), &paths::RESULT);
if is_type_diagnostic_item(cx, cx.tables.expr_ty(&ok_args[0]), sym!(result_type));
let result_type = cx.tables.expr_ty(&ok_args[0]);
if let Some(error_type) = get_error_type(cx, result_type);
if has_debug_impl(error_type, cx);
@ -2455,8 +2513,8 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
unwrap_args: &'tcx [hir::Expr<'_>],
) {
// lint if the caller of `map()` is an `Option`
let is_option = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::OPTION);
let is_result = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::RESULT);
let is_option = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(option_type));
let is_result = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(result_type));
if is_option || is_result {
// Don't make a suggestion that may fail to compile due to mutably borrowing
@ -2517,38 +2575,78 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
}
}
/// lint use of `_.map_or(None, _)` for `Option`s
/// lint use of `_.map_or(None, _)` for `Option`s and `Result`s
fn lint_map_or_none<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
expr: &'tcx hir::Expr<'_>,
map_or_args: &'tcx [hir::Expr<'_>],
) {
if match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &paths::OPTION) {
// check if the first non-self argument to map_or() is None
let map_or_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].kind {
let is_option = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_or_args[0]), sym!(option_type));
let is_result = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_or_args[0]), sym!(result_type));
// There are two variants of this `map_or` lint:
// (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
// (2) using `map_or` as a combinator instead of `and_then`
//
// (For this lint) we don't care if any other type calls `map_or`
if !is_option && !is_result {
return;
}
let (lint_name, msg, instead, hint) = {
let default_arg_is_none = if let hir::ExprKind::Path(ref qpath) = map_or_args[1].kind {
match_qpath(qpath, &paths::OPTION_NONE)
} else {
return;
};
if !default_arg_is_none {
// nothing to lint!
return;
}
let f_arg_is_some = if let hir::ExprKind::Path(ref qpath) = map_or_args[2].kind {
match_qpath(qpath, &paths::OPTION_SOME)
} else {
false
};
if map_or_arg_is_none {
// lint message
if is_option {
let self_snippet = snippet(cx, map_or_args[0].span, "..");
let func_snippet = snippet(cx, map_or_args[2].span, "..");
let msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \
`and_then(f)` instead";
let map_or_self_snippet = snippet(cx, map_or_args[0].span, "..");
let map_or_func_snippet = snippet(cx, map_or_args[2].span, "..");
let hint = format!("{0}.and_then({1})", map_or_self_snippet, map_or_func_snippet);
span_lint_and_sugg(
cx,
(
OPTION_MAP_OR_NONE,
expr.span,
msg,
"try using `and_then` instead",
format!("{0}.and_then({1})", self_snippet, func_snippet),
)
} else if f_arg_is_some {
let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \
`ok()` instead";
let self_snippet = snippet(cx, map_or_args[0].span, "..");
(
RESULT_MAP_OR_INTO_OPTION,
msg,
"try using `ok` instead",
format!("{0}.ok()", self_snippet),
)
} else {
// nothing to lint!
return;
}
};
span_lint_and_sugg(
cx,
lint_name,
expr.span,
msg,
instead,
hint,
Applicability::MachineApplicable,
);
}
}
}
/// Lint use of `_.and_then(|x| Some(y))` for `Option`s
@ -3133,10 +3231,7 @@ fn is_maybe_uninit_ty_valid(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool {
match ty.kind {
ty::Array(ref component, _) => is_maybe_uninit_ty_valid(cx, component),
ty::Tuple(ref types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)),
ty::Adt(ref adt, _) => {
// needs to be a MaybeUninit
match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT)
},
ty::Adt(ref adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT),
_ => false,
}
}
@ -3159,6 +3254,8 @@ fn lint_option_as_ref_deref<'a, 'tcx>(
map_args: &[hir::Expr<'_>],
is_mut: bool,
) {
let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
let option_ty = cx.tables.expr_ty(&as_ref_args[0]);
if !match_type(cx, option_ty, &paths::OPTION) {
return;
@ -3181,8 +3278,10 @@ fn lint_option_as_ref_deref<'a, 'tcx>(
hir::ExprKind::Closure(_, _, body_id, _, _) => {
let closure_body = cx.tcx.hir().body(body_id);
let closure_expr = remove_blocks(&closure_body.value);
match &closure_expr.kind {
hir::ExprKind::MethodCall(_, _, args) => {
if_chain! {
if let hir::ExprKind::MethodCall(_, _, args) = &closure_expr.kind;
if args.len() == 1;
if let hir::ExprKind::Path(qpath) = &args[0].kind;
if let hir::def::Res::Local(local_id) = cx.tables.qpath_res(qpath, args[0].hir_id);
@ -3197,23 +3296,38 @@ fn lint_option_as_ref_deref<'a, 'tcx>(
}
}
},
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => {
if_chain! {
if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner1) = inner.kind;
if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner2) = inner1.kind;
if let hir::ExprKind::Path(ref qpath) = inner2.kind;
if let hir::def::Res::Local(local_id) = cx.tables.qpath_res(qpath, inner2.hir_id);
then {
closure_body.params[0].pat.hir_id == local_id
} else {
false
}
}
},
_ => false,
}
},
_ => false,
};
if is_deref {
let current_method = if is_mut {
".as_mut().map(DerefMut::deref_mut)"
format!(".as_mut().map({})", snippet(cx, map_args[1].span, ".."))
} else {
".as_ref().map(Deref::deref)"
format!(".as_ref().map({})", snippet(cx, map_args[1].span, ".."))
};
let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint);
let suggestion = format!("try using {} instead", method_hint);
let msg = format!(
"called `{0}` (or with one of deref aliases) on an Option value. \
This can be done more directly by calling `{1}` instead",
"called `{0}` on an Option value. This can be done more directly \
by calling `{1}` instead",
current_method, hint
);
span_lint_and_sugg(
@ -3231,7 +3345,7 @@ fn lint_option_as_ref_deref<'a, 'tcx>(
/// Given a `Result<T, E>` type, return its error type (`E`).
fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option<Ty<'a>> {
match ty.kind {
ty::Adt(_, substs) if match_type(cx, ty, &paths::RESULT) => substs.types().nth(1),
ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym!(result_type)) => substs.types().nth(1),
_ => None,
}
}
@ -3259,38 +3373,45 @@ const CONVENTIONS: [(Convention, &[SelfKind]); 7] = [
(Convention::StartsWith("to_"), &[SelfKind::Ref]),
];
const FN_HEADER: hir::FnHeader = hir::FnHeader {
unsafety: hir::Unsafety::Normal,
constness: hir::Constness::NotConst,
asyncness: hir::IsAsync::NotAsync,
abi: rustc_target::spec::abi::Abi::Rust,
};
#[rustfmt::skip]
const TRAIT_METHODS: [(&str, usize, SelfKind, OutType, &str); 30] = [
("add", 2, SelfKind::Value, OutType::Any, "std::ops::Add"),
("as_mut", 1, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"),
("as_ref", 1, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"),
("bitand", 2, SelfKind::Value, OutType::Any, "std::ops::BitAnd"),
("bitor", 2, SelfKind::Value, OutType::Any, "std::ops::BitOr"),
("bitxor", 2, SelfKind::Value, OutType::Any, "std::ops::BitXor"),
("borrow", 1, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"),
("borrow_mut", 1, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"),
("clone", 1, SelfKind::Ref, OutType::Any, "std::clone::Clone"),
("cmp", 2, SelfKind::Ref, OutType::Any, "std::cmp::Ord"),
("default", 0, SelfKind::No, OutType::Any, "std::default::Default"),
("deref", 1, SelfKind::Ref, OutType::Ref, "std::ops::Deref"),
("deref_mut", 1, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"),
("div", 2, SelfKind::Value, OutType::Any, "std::ops::Div"),
("drop", 1, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"),
("eq", 2, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"),
("from_iter", 1, SelfKind::No, OutType::Any, "std::iter::FromIterator"),
("from_str", 1, SelfKind::No, OutType::Any, "std::str::FromStr"),
("hash", 2, SelfKind::Ref, OutType::Unit, "std::hash::Hash"),
("index", 2, SelfKind::Ref, OutType::Ref, "std::ops::Index"),
("index_mut", 2, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"),
("into_iter", 1, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"),
("mul", 2, SelfKind::Value, OutType::Any, "std::ops::Mul"),
("neg", 1, SelfKind::Value, OutType::Any, "std::ops::Neg"),
("next", 1, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"),
("not", 1, SelfKind::Value, OutType::Any, "std::ops::Not"),
("rem", 2, SelfKind::Value, OutType::Any, "std::ops::Rem"),
("shl", 2, SelfKind::Value, OutType::Any, "std::ops::Shl"),
("shr", 2, SelfKind::Value, OutType::Any, "std::ops::Shr"),
("sub", 2, SelfKind::Value, OutType::Any, "std::ops::Sub"),
const TRAIT_METHODS: [(&str, usize, &hir::FnHeader, SelfKind, OutType, &str); 30] = [
("add", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Add"),
("as_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::convert::AsMut"),
("as_ref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::convert::AsRef"),
("bitand", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitAnd"),
("bitor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitOr"),
("bitxor", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::BitXor"),
("borrow", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::borrow::Borrow"),
("borrow_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::borrow::BorrowMut"),
("clone", 1, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::clone::Clone"),
("cmp", 2, &FN_HEADER, SelfKind::Ref, OutType::Any, "std::cmp::Ord"),
("default", 0, &FN_HEADER, SelfKind::No, OutType::Any, "std::default::Default"),
("deref", 1, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::ops::Deref"),
("deref_mut", 1, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::ops::DerefMut"),
("div", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Div"),
("drop", 1, &FN_HEADER, SelfKind::RefMut, OutType::Unit, "std::ops::Drop"),
("eq", 2, &FN_HEADER, SelfKind::Ref, OutType::Bool, "std::cmp::PartialEq"),
("from_iter", 1, &FN_HEADER, SelfKind::No, OutType::Any, "std::iter::FromIterator"),
("from_str", 1, &FN_HEADER, SelfKind::No, OutType::Any, "std::str::FromStr"),
("hash", 2, &FN_HEADER, SelfKind::Ref, OutType::Unit, "std::hash::Hash"),
("index", 2, &FN_HEADER, SelfKind::Ref, OutType::Ref, "std::ops::Index"),
("index_mut", 2, &FN_HEADER, SelfKind::RefMut, OutType::Ref, "std::ops::IndexMut"),
("into_iter", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::iter::IntoIterator"),
("mul", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Mul"),
("neg", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Neg"),
("next", 1, &FN_HEADER, SelfKind::RefMut, OutType::Any, "std::iter::Iterator"),
("not", 1, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Not"),
("rem", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Rem"),
("shl", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Shl"),
("shr", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Shr"),
("sub", 2, &FN_HEADER, SelfKind::Value, OutType::Any, "std::ops::Sub"),
];
#[rustfmt::skip]
@ -3324,12 +3445,12 @@ enum SelfKind {
impl SelfKind {
fn matches<'a>(self, cx: &LateContext<'_, 'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
fn matches_value(parent_ty: Ty<'_>, ty: Ty<'_>) -> bool {
fn matches_value<'a>(cx: &LateContext<'_, 'a>, parent_ty: Ty<'_>, ty: Ty<'_>) -> bool {
if ty == parent_ty {
true
} else if ty.is_box() {
ty.boxed_ty() == parent_ty
} else if ty.is_rc() || ty.is_arc() {
} else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) {
if let ty::Adt(_, substs) = ty.kind {
substs.types().next().map_or(false, |t| t == parent_ty)
} else {
@ -3363,7 +3484,7 @@ impl SelfKind {
}
match self {
Self::Value => matches_value(parent_ty, ty),
Self::Value => matches_value(cx, parent_ty, ty),
Self::Ref => matches_ref(cx, hir::Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty),
Self::RefMut => matches_ref(cx, hir::Mutability::Mut, parent_ty, ty),
Self::No => ty != parent_ty,
@ -3503,3 +3624,9 @@ fn lint_filetype_is_file(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &
let help_msg = format!("use `{}FileType::is_dir()` instead", help_unary);
span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, &help_msg);
}
fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
expected.constness == actual.constness
&& expected.unsafety == actual.unsafety
&& expected.asyncness == actual.asyncness
}

View File

@ -1,11 +1,11 @@
use crate::utils::{differing_macro_contexts, paths, snippet_with_applicability, span_lint_and_then};
use crate::utils::{is_copy, match_type};
use rustc::hir::map::Map;
use crate::utils::{differing_macro_contexts, snippet_with_applicability, span_lint_and_then};
use crate::utils::{is_copy, is_type_diagnostic_item};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_path, NestedVisitorMap, Visitor};
use rustc_hir::{self, HirId, Path};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;
@ -20,7 +20,7 @@ pub(super) fn lint<'a, 'tcx>(
map_span: Span,
) {
// lint if the caller of `map()` is an `Option`
if match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::OPTION) {
if is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(option_type)) {
if !is_copy(cx, cx.tables.expr_ty(&unwrap_args[1])) {
// Do not lint if the `map` argument uses identifiers in the `map`
// argument that are also used in the `unwrap_or` argument

View File

@ -1,11 +1,11 @@
use crate::utils::paths;
use crate::utils::usage::mutated_variables;
use crate::utils::{match_qpath, match_trait_method, span_lint};
use rustc::hir::map::Map;
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;
use if_chain::if_chain;

View File

@ -1,5 +1,4 @@
use if_chain::if_chain;
use rustc::ty;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
@ -8,6 +7,7 @@ use rustc_hir::{
TyKind, UnOp,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::{ExpnKind, Span};
@ -57,10 +57,9 @@ declare_clippy_lint! {
///
/// **Example:**
/// ```rust
/// # use core::f32::NAN;
/// # let x = 1.0;
///
/// if x == NAN { }
/// if x == f32::NAN { }
/// ```
pub CMP_NAN,
correctness,
@ -370,15 +369,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints {
return;
}
}
let (lint, msg) = if is_named_constant(cx, left) || is_named_constant(cx, right) {
(FLOAT_CMP_CONST, "strict comparison of `f32` or `f64` constant")
} else {
(FLOAT_CMP, "strict comparison of `f32` or `f64`")
};
let is_comparing_arrays = is_array(cx, left) || is_array(cx, right);
let (lint, msg) = get_lint_and_message(
is_named_constant(cx, left) || is_named_constant(cx, right),
is_comparing_arrays,
);
span_lint_and_then(cx, lint, expr.span, msg, |db| {
let lhs = Sugg::hir(cx, left, "..");
let rhs = Sugg::hir(cx, right, "..");
if !is_comparing_arrays {
db.span_suggestion(
expr.span,
"consider comparing them within some error",
@ -389,7 +389,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints {
),
Applicability::HasPlaceholders, // snippet
);
db.span_note(expr.span, "`std::f32::EPSILON` and `std::f64::EPSILON` are available.");
}
db.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error`");
});
} else if op == BinOpKind::Rem && is_integer_const(cx, right, 1) {
span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0");
@ -441,6 +442,31 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints {
}
}
fn get_lint_and_message(
is_comparing_constants: bool,
is_comparing_arrays: bool,
) -> (&'static rustc_lint::Lint, &'static str) {
if is_comparing_constants {
(
FLOAT_CMP_CONST,
if is_comparing_arrays {
"strict comparison of `f32` or `f64` constant arrays"
} else {
"strict comparison of `f32` or `f64` constant"
},
)
} else {
(
FLOAT_CMP,
if is_comparing_arrays {
"strict comparison of `f32` or `f64` arrays"
} else {
"strict comparison of `f32` or `f64`"
},
)
}
}
fn check_nan(cx: &LateContext<'_, '_>, expr: &Expr<'_>, cmp_expr: &Expr<'_>) {
if_chain! {
if !in_constant(cx, cmp_expr.hir_id);
@ -457,7 +483,7 @@ fn check_nan(cx: &LateContext<'_, '_>, expr: &Expr<'_>, cmp_expr: &Expr<'_>) {
cx,
CMP_NAN,
cmp_expr.span,
"doomed comparison with `NAN`, use `std::{f32,f64}::is_nan()` instead",
"doomed comparison with `NAN`, use `{f32,f64}::is_nan()` instead",
);
}
}
@ -476,6 +502,11 @@ fn is_allowed<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) -> boo
match constant(cx, cx.tables, expr) {
Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(),
Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(),
Some((Constant::Vec(vec), _)) => vec.iter().all(|f| match f {
Constant::F32(f) => *f == 0.0 || (*f).is_infinite(),
Constant::F64(f) => *f == 0.0 || (*f).is_infinite(),
_ => false,
}),
_ => false,
}
}
@ -500,7 +531,17 @@ fn is_signum(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
}
fn is_float(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
matches!(walk_ptrs_ty(cx.tables.expr_ty(expr)).kind, ty::Float(_))
let value = &walk_ptrs_ty(cx.tables.expr_ty(expr)).kind;
if let ty::Array(arr_ty, _) = value {
return matches!(arr_ty.kind, ty::Float(_));
};
matches!(value, ty::Float(_))
}
fn is_array(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
matches!(&walk_ptrs_ty(cx.tables.expr_ty(expr)).kind, ty::Array(_, _))
}
fn check_to_owned(cx: &LateContext<'_, '_>, expr: &Expr<'_>, other: &Expr<'_>) {

View File

@ -3,7 +3,6 @@ use crate::utils::{
span_lint_and_then,
};
use if_chain::if_chain;
use rustc::lint::in_external_macro;
use rustc_ast::ast::{
BindingMode, Block, Expr, ExprKind, GenericParamKind, Generics, Lit, LitFloatType, LitIntType, LitKind, Mutability,
NodeId, Pat, PatKind, StmtKind, UnOp,
@ -12,6 +11,7 @@ use rustc_ast::visit::{walk_expr, FnKind, Visitor};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

View File

@ -1,9 +1,9 @@
use crate::utils::{fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method};
use rustc::lint::in_external_macro;
use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_mir::transform::qualify_min_const_fn::is_min_const_fn;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

View File

@ -7,11 +7,11 @@
use crate::utils::span_lint;
use if_chain::if_chain;
use rustc::ty;
use rustc_ast::ast::{self, MetaItem, MetaItemKind};
use rustc_ast::attr;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;

View File

@ -81,7 +81,7 @@ declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline {
fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, it: &'tcx hir::Item<'_>) {
if rustc::lint::in_external_macro(cx.sess(), it.span) || is_executable(cx) {
if rustc_middle::lint::in_external_macro(cx.sess(), it.span) || is_executable(cx) {
return;
}
@ -130,8 +130,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingInline {
}
fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
use rustc::ty::{ImplContainer, TraitContainer};
if rustc::lint::in_external_macro(cx.sess(), impl_item.span) || is_executable(cx) {
use rustc_middle::ty::{ImplContainer, TraitContainer};
if rustc_middle::lint::in_external_macro(cx.sess(), impl_item.span) || is_executable(cx) {
return;
}

View File

@ -1,9 +1,9 @@
use crate::consts::{constant, Constant};
use crate::utils::{sext, span_lint_and_then};
use if_chain::if_chain;
use rustc::ty::{self};
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use std::fmt::Display;

View File

@ -1,7 +1,7 @@
use crate::utils::{match_def_path, paths, span_lint, trait_ref_of_method, walk_ptrs_ty};
use rustc::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut};
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

View File

@ -1,10 +1,10 @@
use crate::utils::{higher, span_lint};
use rustc::hir::map::Map;
use rustc::lint::in_external_macro;
use rustc::ty;
use rustc_hir as hir;
use rustc_hir::intravisit;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {

View File

@ -1,8 +1,8 @@
use crate::utils::span_lint;
use rustc::ty::subst::Subst;
use rustc::ty::{self, Ty};
use rustc_hir::{print, BorrowKind, Expr, ExprKind, Mutability};
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
@ -34,7 +34,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnecessaryMutPassed {
cx,
arguments,
cx.tables.expr_ty(fn_expr),
&print::to_string(print::NO_ANN, |s| s.print_qpath(path, false)),
&rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
);
}
},

View File

@ -1,10 +1,10 @@
use crate::utils::{is_direct_expn_of, span_lint};
use if_chain::if_chain;
use rustc::hir::map::Map;
use rustc::ty;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability, StmtKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;
@ -53,7 +53,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DebugAssertWithMutCall {
}
//HACK(hellow554): remove this when #4694 is implemented
#[allow(clippy::cognitive_complexity)]
fn extract_call<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, e: &'tcx Expr<'_>) -> Option<Span> {
if_chain! {
if let ExprKind::Block(ref block, _) = e.kind;

View File

@ -3,10 +3,10 @@
//! This lint is **warn** by default
use crate::utils::{match_type, paths, span_lint};
use rustc::ty::{self, Ty};
use rustc_ast::ast;
use rustc_hir::Expr;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {

View File

@ -3,13 +3,15 @@
//! This lint is **warn** by default
use crate::utils::sugg::Sugg;
use crate::utils::{higher, parent_node_is_if_expr, span_lint, span_lint_and_sugg};
use crate::utils::{higher, parent_node_is_if_expr, snippet_with_applicability, span_lint, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind};
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;
use rustc_span::Span;
declare_clippy_lint! {
/// **What it does:** Checks for expressions of the form `if c { true } else {
@ -188,6 +190,34 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
}
}
struct ExpressionInfoWithSpan {
one_side_is_unary_not: bool,
left_span: Span,
right_span: Span,
}
fn is_unary_not(e: &Expr<'_>) -> (bool, Span) {
if_chain! {
if let ExprKind::Unary(unop, operand) = e.kind;
if let UnOp::UnNot = unop;
then {
return (true, operand.span);
}
};
(false, e.span)
}
fn one_side_is_unary_not<'tcx>(left_side: &'tcx Expr<'_>, right_side: &'tcx Expr<'_>) -> ExpressionInfoWithSpan {
let left = is_unary_not(left_side);
let right = is_unary_not(right_side);
ExpressionInfoWithSpan {
one_side_is_unary_not: left.0 != right.0,
left_span: left.1,
right_span: right.1,
}
}
fn check_comparison<'a, 'tcx>(
cx: &LateContext<'a, 'tcx>,
e: &'tcx Expr<'_>,
@ -199,10 +229,30 @@ fn check_comparison<'a, 'tcx>(
) {
use self::Expression::{Bool, Other};
if let ExprKind::Binary(_, ref left_side, ref right_side) = e.kind {
if let ExprKind::Binary(op, ref left_side, ref right_side) = e.kind {
let (l_ty, r_ty) = (cx.tables.expr_ty(left_side), cx.tables.expr_ty(right_side));
if l_ty.is_bool() && r_ty.is_bool() {
let mut applicability = Applicability::MachineApplicable;
if let BinOpKind::Eq = op.node {
let expression_info = one_side_is_unary_not(&left_side, &right_side);
if expression_info.one_side_is_unary_not {
span_lint_and_sugg(
cx,
BOOL_COMPARISON,
e.span,
"This comparison might be written more concisely",
"try simplifying it as shown",
format!(
"{} != {}",
snippet_with_applicability(cx, expression_info.left_span, "..", &mut applicability),
snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability)
),
applicability,
)
}
}
match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
(Bool(true), Other) => left_true.map_or((), |(h, m)| {
suggest_bool_comparison(cx, e, right_side, applicability, m, h)

View File

@ -4,11 +4,11 @@
use crate::utils::{snippet_opt, span_lint_and_then};
use if_chain::if_chain;
use rustc::ty;
use rustc::ty::adjustment::{Adjust, Adjustment};
use rustc_errors::Applicability;
use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, HirId, Item, Mutability, Pat, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment};
use rustc_session::{declare_tool_lint, impl_lint_pass};
declare_clippy_lint! {

View File

@ -4,7 +4,6 @@ use crate::utils::{
snippet, snippet_opt, span_lint_and_then,
};
use if_chain::if_chain;
use rustc::ty::{self, TypeFoldable};
use rustc_ast::ast::Attribute;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{Applicability, DiagnosticBuilder};
@ -12,8 +11,9 @@ use rustc_hir::intravisit::FnKind;
use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, ItemKind, Node, PatKind, QPath, TyKind};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, TypeFoldable};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{Span, Symbol};
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::misc::can_type_implement_copy;
@ -113,8 +113,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.to_vec())
.filter(|p| !p.is_global())
.filter_map(|pred| {
if let ty::Predicate::Trait(poly_trait_ref, _) = pred {
.filter_map(|obligation| {
if let ty::Predicate::Trait(poly_trait_ref, _) = obligation.predicate {
if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_bound_vars()
{
return None;
@ -214,7 +214,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
let deref_span = spans_need_deref.get(&canonical_id);
if_chain! {
if is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type"));
if is_type_diagnostic_item(cx, ty, sym!(vec_type));
if let Some(clone_spans) =
get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]);
if let TyKind::Path(QPath::Resolved(_, ref path)) = input.kind;

View File

@ -1,7 +1,7 @@
use crate::utils::span_lint;
use rustc::ty;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {

View File

@ -1,7 +1,7 @@
use if_chain::if_chain;
use rustc::lint::in_external_macro;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use crate::utils::{self, paths, span_lint};
@ -25,13 +25,13 @@ declare_clippy_lint! {
///
/// // Bad
/// let a = 1.0;
/// let b = std::f64::NAN;
/// let b = f64::NAN;
///
/// let _not_less_or_equal = !(a <= b);
///
/// // Good
/// let a = 1.0;
/// let b = std::f64::NAN;
/// let b = f64::NAN;
///
/// let _not_less_or_equal = match a.partial_cmp(&b) {
/// None | Some(Ordering::Greater) => true,

View File

@ -2,13 +2,13 @@ use crate::utils::paths;
use crate::utils::sugg::DiagnosticBuilderExt;
use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_hir_and_then};
use if_chain::if_chain;
use rustc::lint::in_external_macro;
use rustc::ty::{self, Ty};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::HirIdSet;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
@ -100,7 +100,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
} = item.kind
{
for assoc_item in items {
if let hir::AssocItemKind::Method { has_self: false } = assoc_item.kind {
if let hir::AssocItemKind::Fn { has_self: false } = assoc_item.kind {
let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
if in_external_macro(cx.sess(), impl_item.span) {
return;

View File

@ -4,11 +4,11 @@
use std::ptr;
use rustc::ty::adjustment::Adjust;
use rustc::ty::{Ty, TypeFlags};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp};
use rustc_lint::{LateContext, LateLintPass, Lint};
use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{Ty, TypeFlags};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{InnerSpan, Span, DUMMY_SP};
use rustc_typeck::hir_ty_to_ty;

View File

@ -6,16 +6,16 @@ use crate::utils::{
walk_ptrs_hir_ty,
};
use if_chain::if_chain;
use rustc::ty;
use rustc_errors::Applicability;
use rustc_hir::{
BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind,
Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::{MultiSpan, Symbol};
use rustc_span::MultiSpan;
use std::borrow::Cow;
declare_clippy_lint! {
@ -153,7 +153,7 @@ fn check_fn(cx: &LateContext<'_, '_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_
for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() {
if let ty::Ref(_, ty, Mutability::Not) = ty.kind {
if is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type")) {
if is_type_diagnostic_item(cx, ty, sym!(vec_type)) {
let mut ty_snippet = None;
if_chain! {
if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).kind;

View File

@ -5,10 +5,10 @@ use rustc_hir::{def, BindingAnnotation, Block, Expr, ExprKind, MatchSource, PatK
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use crate::utils::paths::{OPTION, OPTION_NONE};
use crate::utils::sugg::Sugg;
use crate::utils::{
higher, match_def_path, match_qpath, match_type, snippet_with_applicability, span_lint_and_sugg, SpanlessEq,
higher, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet_with_applicability,
span_lint_and_sugg, SpanlessEq,
};
declare_clippy_lint! {
@ -141,7 +141,7 @@ impl QuestionMark {
fn is_option(cx: &LateContext<'_, '_>, expression: &Expr<'_>) -> bool {
let expr_ty = cx.tables.expr_ty(expression);
match_type(cx, expr_ty, &OPTION)
is_type_diagnostic_item(cx, expr_ty, sym!(option_type))
}
fn expression_returns_none(cx: &LateContext<'_, '_>, expression: &Expr<'_>) -> bool {
@ -158,7 +158,7 @@ impl QuestionMark {
if let Res::Def(DefKind::Ctor(def::CtorOf::Variant, def::CtorKind::Const), def_id) =
cx.tables.qpath_res(qp, expression.hir_id)
{
return match_def_path(cx, def_id, &OPTION_NONE);
return match_def_path(cx, def_id, &paths::OPTION_NONE);
}
false

View File

@ -3,19 +3,19 @@ use crate::utils::{
span_lint_hir_and_then, walk_ptrs_ty_depth,
};
use if_chain::if_chain;
use rustc::mir::{
self, traversal,
visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _},
};
use rustc::ty::{self, fold::TypeVisitor, Ty};
use rustc_data_structures::{fx::FxHashMap, transitive_relation::TransitiveRelation};
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{def_id, Body, FnDecl, HirId};
use rustc_index::bit_set::{BitSet, HybridBitSet};
use rustc_lint::{LateContext, LateLintPass};
use rustc_mir::dataflow::generic::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor};
use rustc_middle::mir::{
self, traversal,
visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _},
};
use rustc_middle::ty::{self, fold::TypeVisitor, Ty};
use rustc_mir::dataflow::BottomValue;
use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::{BytePos, Span};
use std::convert::TryFrom;
@ -80,20 +80,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for RedundantClone {
let def_id = cx.tcx.hir().body_owner_def_id(body.id());
// Building MIR for `fn`s with unsatisfiable preds results in ICE.
if fn_has_unsatisfiable_preds(cx, def_id) {
if fn_has_unsatisfiable_preds(cx, def_id.to_def_id()) {
return;
}
let mir = cx.tcx.optimized_mir(def_id);
let mir = cx.tcx.optimized_mir(def_id.to_def_id());
let mir_read_only = mir.unwrap_read_only();
let maybe_storage_live_result = MaybeStorageLive
.into_engine(cx.tcx, mir, def_id)
.into_engine(cx.tcx, mir, def_id.to_def_id())
.iterate_to_fixpoint()
.into_results_cursor(mir);
let mut possible_borrower = {
let mut vis = PossibleBorrowerVisitor::new(cx, mir);
vis.visit_body(mir_read_only);
vis.visit_body(&mir_read_only);
vis.into_map(cx, maybe_storage_live_result)
};
@ -335,12 +335,15 @@ fn base_local_and_movability<'tcx>(
mir: &mir::Body<'tcx>,
place: mir::Place<'tcx>,
) -> Option<(mir::Local, CannotMoveOut)> {
use rustc::mir::PlaceRef;
use rustc_middle::mir::PlaceRef;
// Dereference. You cannot move things out from a borrowed value.
let mut deref = false;
// Accessing a field of an ADT that has `Drop`. Moving the field out will cause E0509.
let mut field = false;
// If projection is a slice index then clone can be removed only if the
// underlying type implements Copy
let mut slice = false;
let PlaceRef { local, mut projection } = place.as_ref();
while let [base @ .., elem] = projection {
@ -348,9 +351,11 @@ fn base_local_and_movability<'tcx>(
deref |= matches!(elem, mir::ProjectionElem::Deref);
field |= matches!(elem, mir::ProjectionElem::Field(..))
&& has_drop(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty);
slice |= matches!(elem, mir::ProjectionElem::Index(..))
&& !is_copy(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty);
}
Some((local, deref || field))
Some((local, deref || field || slice))
}
struct LocalUseVisitor {
@ -437,7 +442,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
_block: mir::BasicBlock,
_func: &mir::Operand<'tcx>,
_args: &[mir::Operand<'tcx>],
_return_place: &mir::Place<'tcx>,
_return_place: mir::Place<'tcx>,
) {
// Nothing to do when a call returns successfully
}
@ -556,7 +561,7 @@ impl TypeVisitor<'_> for ContainsRegion {
}
fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
use rustc::mir::Rvalue::{Aggregate, BinaryOp, Cast, CheckedBinaryOp, Repeat, UnaryOp, Use};
use rustc_middle::mir::Rvalue::{Aggregate, BinaryOp, Cast, CheckedBinaryOp, Repeat, UnaryOp, Use};
let mut visit_op = |op: &mir::Operand<'_>| match op {
mir::Operand::Copy(p) | mir::Operand::Move(p) => visit(p.local),

View File

@ -1,103 +0,0 @@
use crate::utils::{match_def_path, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, ExprKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
/// **What it does:** Checks for usage of standard library
/// `const`s that could be replaced by `const fn`s.
///
/// **Why is this bad?** `const fn`s exist
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let x = std::u32::MIN;
/// let y = std::u32::MAX;
/// ```
///
/// Could be written:
///
/// ```rust
/// let x = u32::min_value();
/// let y = u32::max_value();
/// ```
pub REPLACE_CONSTS,
pedantic,
"Lint usages of standard library `const`s that could be replaced by `const fn`s"
}
declare_lint_pass!(ReplaceConsts => [REPLACE_CONSTS]);
fn in_pattern(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
let map = &cx.tcx.hir();
let parent_id = map.get_parent_node(expr.hir_id);
if let Some(node) = map.find(parent_id) {
if let Node::Pat(_) = node {
return true;
}
}
false
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ReplaceConsts {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
if let ExprKind::Path(ref qp) = expr.kind;
if let Res::Def(DefKind::Const, def_id) = cx.tables.qpath_res(qp, expr.hir_id);
// Do not lint within patterns as function calls are disallowed in them
if !in_pattern(cx, expr);
then {
for &(ref const_path, repl_snip) in &REPLACEMENTS {
if match_def_path(cx, def_id, const_path) {
span_lint_and_sugg(
cx,
REPLACE_CONSTS,
expr.span,
&format!("using `{}`", const_path.last().expect("empty path")),
"try this",
repl_snip.to_string(),
Applicability::MachineApplicable,
);
return;
}
}
}
}
}
}
const REPLACEMENTS: [([&str; 3], &str); 24] = [
// Min
(["core", "isize", "MIN"], "isize::min_value()"),
(["core", "i8", "MIN"], "i8::min_value()"),
(["core", "i16", "MIN"], "i16::min_value()"),
(["core", "i32", "MIN"], "i32::min_value()"),
(["core", "i64", "MIN"], "i64::min_value()"),
(["core", "i128", "MIN"], "i128::min_value()"),
(["core", "usize", "MIN"], "usize::min_value()"),
(["core", "u8", "MIN"], "u8::min_value()"),
(["core", "u16", "MIN"], "u16::min_value()"),
(["core", "u32", "MIN"], "u32::min_value()"),
(["core", "u64", "MIN"], "u64::min_value()"),
(["core", "u128", "MIN"], "u128::min_value()"),
// Max
(["core", "isize", "MAX"], "isize::max_value()"),
(["core", "i8", "MAX"], "i8::max_value()"),
(["core", "i16", "MAX"], "i16::max_value()"),
(["core", "i32", "MAX"], "i32::max_value()"),
(["core", "i64", "MAX"], "i64::max_value()"),
(["core", "i128", "MAX"], "i128::max_value()"),
(["core", "usize", "MAX"], "usize::max_value()"),
(["core", "u8", "MAX"], "u8::max_value()"),
(["core", "u16", "MAX"], "u16::max_value()"),
(["core", "u32", "MAX"], "u32::max_value()"),
(["core", "u64", "MAX"], "u64::max_value()"),
(["core", "u128", "MAX"], "u128::max_value()"),
];

View File

@ -1,9 +1,9 @@
use if_chain::if_chain;
use rustc::lint::in_external_macro;
use rustc_ast::ast;
use rustc_ast::visit::FnKind;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::BytePos;

View File

@ -1,13 +1,13 @@
use crate::reexport::Name;
use crate::utils::{contains_name, higher, iter_input_pats, snippet, span_lint_and_then};
use rustc::lint::in_external_macro;
use rustc::ty;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
Block, Body, Expr, ExprKind, FnDecl, Guard, HirId, Local, MutTy, Pat, PatKind, Path, QPath, StmtKind, Ty, TyKind,
UnOp,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

View File

@ -1,12 +1,12 @@
use crate::utils::sugg::Sugg;
use crate::utils::{get_enclosing_block, match_qpath, span_lint_and_then, SpanlessEq};
use if_chain::if_chain;
use rustc::hir::map::Map;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, NestedVisitorMap, Visitor};
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, QPath, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, Lint};
use rustc_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::Symbol;

View File

@ -1,7 +1,7 @@
use rustc::lint::in_external_macro;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;

View File

@ -1,9 +1,9 @@
use crate::utils::{get_trait_def_id, span_lint, trait_ref_of_method};
use if_chain::if_chain;
use rustc::hir::map::Map;
use rustc_hir as hir;
use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
@ -54,7 +54,7 @@ declare_lint_pass!(SuspiciousImpl => [SUSPICIOUS_ARITHMETIC_IMPL, SUSPICIOUS_OP_
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for SuspiciousImpl {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) {
if let hir::ExprKind::Binary(binop, _, _) = expr.kind {
if let hir::ExprKind::Binary(binop, _, _) | hir::ExprKind::AssignOp(binop, ..) = expr.kind {
match binop.node {
hir::BinOpKind::Eq
| hir::BinOpKind::Lt
@ -65,14 +65,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for SuspiciousImpl {
_ => {},
}
// Check if the binary expression is part of another bi/unary expression
// as a child node
// or operator assignment as a child node
let mut parent_expr = cx.tcx.hir().get_parent_node(expr.hir_id);
while parent_expr != hir::CRATE_HIR_ID {
if let hir::Node::Expr(e) = cx.tcx.hir().get(parent_expr) {
match e.kind {
hir::ExprKind::Binary(..)
| hir::ExprKind::Unary(hir::UnOp::UnNot, _)
| hir::ExprKind::Unary(hir::UnOp::UnNeg, _) => return,
| hir::ExprKind::Unary(hir::UnOp::UnNeg, _)
| hir::ExprKind::AssignOp(..) => return,
_ => {},
}
}
@ -191,7 +192,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BinaryExprVisitor {
match expr.kind {
hir::ExprKind::Binary(..)
| hir::ExprKind::Unary(hir::UnOp::UnNot, _)
| hir::ExprKind::Unary(hir::UnOp::UnNeg, _) => self.in_binary_expr = true,
| hir::ExprKind::Unary(hir::UnOp::UnNeg, _)
| hir::ExprKind::AssignOp(..) => self.in_binary_expr = true,
_ => {},
}

View File

@ -4,12 +4,11 @@ use crate::utils::{
span_lint_and_then, walk_ptrs_ty, SpanlessEq,
};
use if_chain::if_chain;
use rustc::ty;
use rustc_errors::Applicability;
use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Symbol;
declare_clippy_lint! {
/// **What it does:** Checks for manual swapping.
@ -199,7 +198,7 @@ fn check_for_slice<'a>(cx: &LateContext<'_, '_>, lhs1: &'a Expr<'_>, lhs2: &'a E
if matches!(ty.kind, ty::Slice(_))
|| matches!(ty.kind, ty::Array(_, _))
|| is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type"))
|| is_type_diagnostic_item(cx, ty, sym!(vec_type))
|| match_type(cx, ty, &paths::VEC_DEQUE)
{
return Slice::Swappable(lhs1, idx1, idx2);

View File

@ -1,9 +1,9 @@
use crate::utils::{match_def_path, snippet_with_applicability, span_lint_and_sugg};
use if_chain::if_chain;
use rustc::ty;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {

View File

@ -1,5 +1,6 @@
use crate::utils::{in_macro, snippet, span_lint_and_help, SpanlessHash};
use crate::utils::{in_macro, snippet, snippet_with_applicability, span_lint_and_help, SpanlessHash};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_hir::{GenericBound, Generics, WherePredicate};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
@ -41,6 +42,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TraitBounds {
hasher.finish()
};
let mut map = FxHashMap::default();
let mut applicability = Applicability::MaybeIncorrect;
for bound in gen.where_clause.predicates {
if let WherePredicate::BoundPredicate(ref p) = bound {
let h = hash(&p.bounded_ty);
@ -52,13 +54,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TraitBounds {
for b in v.iter() {
if let GenericBound::Trait(ref poly_trait_ref, _) = b {
let path = &poly_trait_ref.trait_ref.path;
hint_string.push_str(&format!(" {} +", path));
hint_string.push_str(&format!(
" {} +",
snippet_with_applicability(cx, path.span, "..", &mut applicability)
));
}
}
for b in p.bounds.iter() {
if let GenericBound::Trait(ref poly_trait_ref, _) = b {
let path = &poly_trait_ref.trait_ref.path;
hint_string.push_str(&format!(" {} +", path));
hint_string.push_str(&format!(
" {} +",
snippet_with_applicability(cx, path.span, "..", &mut applicability)
));
}
}
hint_string.truncate(hint_string.len() - 2);

View File

@ -2,11 +2,11 @@ use crate::utils::{
is_normalizable, last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then, sugg,
};
use if_chain::if_chain;
use rustc::ty::{self, Ty};
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, TyKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use std::borrow::Cow;

View File

@ -1,10 +1,10 @@
use crate::consts::{constant_context, Constant};
use crate::utils::{match_qpath, paths, span_lint};
use if_chain::if_chain;
use rustc::lint::in_external_macro;
use rustc_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {

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