mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-23 13:13:34 +00:00
Merge remote-tracking branch 'upstream/master' into rustup
This commit is contained in:
commit
88c7632659
160 changed files with 2212 additions and 434 deletions
6
.github/workflows/remark.yml
vendored
6
.github/workflows/remark.yml
vendored
|
@ -36,6 +36,12 @@ jobs:
|
|||
- name: Check *.md files
|
||||
run: git ls-files -z '*.md' | xargs -0 -n 1 -I {} ./node_modules/.bin/remark {} -u lint -f > /dev/null
|
||||
|
||||
- name: Linkcheck book
|
||||
run: |
|
||||
rustup toolchain install nightly --component rust-docs
|
||||
curl https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/linkcheck.sh -o linkcheck.sh
|
||||
sh linkcheck.sh clippy --path ./book
|
||||
|
||||
- name: Build mdbook
|
||||
run: mdbook build book
|
||||
|
||||
|
|
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -44,7 +44,7 @@ Current stable, released 2023-04-20
|
|||
|
||||
### Enhancements
|
||||
|
||||
* [`arithmetic_side_effects`]: No longer lints, if safe constant values are used.
|
||||
* [`arithmetic_side_effects`]: No longer lints if safe constant values are used.
|
||||
[#10310](https://github.com/rust-lang/rust-clippy/pull/10310)
|
||||
* [`needless_lifetimes`]: Now works in local macros
|
||||
[#10257](https://github.com/rust-lang/rust-clippy/pull/10257)
|
||||
|
@ -60,39 +60,39 @@ Current stable, released 2023-04-20
|
|||
|
||||
### False Positive Fixes
|
||||
|
||||
* [`explicit_auto_deref`]: Now considers projections, when determining if auto deref is applicable
|
||||
* [`explicit_auto_deref`]: Now considers projections when determining if auto deref is applicable
|
||||
[#10386](https://github.com/rust-lang/rust-clippy/pull/10386)
|
||||
* [`manual_let_else`]: Now considers side effects of branches, before linting
|
||||
* [`manual_let_else`]: Now considers side effects of branches before linting
|
||||
[#10336](https://github.com/rust-lang/rust-clippy/pull/10336)
|
||||
* [`uninlined_format_args`]: No longer lints for arguments with generic parameters
|
||||
[#10343](https://github.com/rust-lang/rust-clippy/pull/10343)
|
||||
* [`needless_lifetimes`]: No longer lints signatures in macros, if the lifetime is a metavariable
|
||||
* [`needless_lifetimes`]: No longer lints signatures in macros if the lifetime is a metavariable
|
||||
[#10380](https://github.com/rust-lang/rust-clippy/pull/10380)
|
||||
* [`len_without_is_empty`]: No longer lints, if `len` as a non-default signature
|
||||
* [`len_without_is_empty`]: No longer lints if `len` as a non-default signature
|
||||
[#10255](https://github.com/rust-lang/rust-clippy/pull/10255)
|
||||
* [`unusual_byte_groupings`]: Relaxed the required restrictions for specific sizes, to reduce false
|
||||
* [`unusual_byte_groupings`]: Relaxed the required restrictions for specific sizes to reduce false
|
||||
positives
|
||||
[#10353](https://github.com/rust-lang/rust-clippy/pull/10353)
|
||||
* [`manual_let_else`]: No longer lints `if-else` blocks if they can divergent
|
||||
[#10332](https://github.com/rust-lang/rust-clippy/pull/10332)
|
||||
* [`expect_used`], [`unwrap_used`], [`dbg_macro`], [`print_stdout`], [`print_stderr`]: No longer lint
|
||||
in test functions, if `allow-expect-in-tests` is set
|
||||
in test functions if `allow-expect-in-tests` is set
|
||||
[#10391](https://github.com/rust-lang/rust-clippy/pull/10391)
|
||||
* [`unnecessary_safety_comment`]: No longer lints code inside macros
|
||||
[#10106](https://github.com/rust-lang/rust-clippy/pull/10106)
|
||||
* [`never_loop`]: No longer lints, for statements following break statements for outer blocks.
|
||||
* [`never_loop`]: No longer lints statements following break statements for outer blocks.
|
||||
[#10311](https://github.com/rust-lang/rust-clippy/pull/10311)
|
||||
|
||||
### Suggestion Fixes/Improvements
|
||||
|
||||
* [`box_default`]: The suggestion now includes the type for trait objects, when needed
|
||||
* [`box_default`]: The suggestion now includes the type for trait objects when needed
|
||||
[#10382](https://github.com/rust-lang/rust-clippy/pull/10382)
|
||||
* [`cast_possible_truncation`]: Now suggests using `try_from` or allowing the lint
|
||||
[#10038](https://github.com/rust-lang/rust-clippy/pull/10038)
|
||||
* [`invalid_regex`]: Regex errors for non-literals or regular strings containing escape sequences will
|
||||
now show the complete error
|
||||
[#10231](https://github.com/rust-lang/rust-clippy/pull/10231)
|
||||
* [`transmutes_expressible_as_ptr_casts`]: The suggestion now works, if the base type is borrowed
|
||||
* [`transmutes_expressible_as_ptr_casts`]: The suggestion now works if the base type is borrowed
|
||||
[#10193](https://github.com/rust-lang/rust-clippy/pull/10193)
|
||||
* [`needless_return`]: Now removes all semicolons on the same line
|
||||
[#10187](https://github.com/rust-lang/rust-clippy/pull/10187)
|
||||
|
@ -113,7 +113,7 @@ Current stable, released 2023-04-20
|
|||
|
||||
### ICE Fixes
|
||||
|
||||
* [`needless_pass_by_value`]: Fixed an ICE, caused by how late bounds were handled
|
||||
* [`needless_pass_by_value`]: Fixed an ICE caused by how late bounds were handled
|
||||
[#10328](https://github.com/rust-lang/rust-clippy/pull/10328)
|
||||
* [`needless_borrow`]: No longer panics on ambiguous projections
|
||||
[#10403](https://github.com/rust-lang/rust-clippy/pull/10403)
|
||||
|
@ -4582,6 +4582,7 @@ Released 2018-09-13
|
|||
[`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
|
||||
[`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
|
||||
[`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
|
||||
[`default_constructed_unit_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_constructed_unit_structs
|
||||
[`default_instead_of_iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_instead_of_iter_empty
|
||||
[`default_numeric_fallback`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback
|
||||
[`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access
|
||||
|
@ -4797,6 +4798,7 @@ Released 2018-09-13
|
|||
[`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
|
||||
[`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
|
||||
[`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
|
||||
[`manual_while_let_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_while_let_some
|
||||
[`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
|
||||
[`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
|
||||
[`map_collect_result_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_collect_result_unit
|
||||
|
@ -4864,6 +4866,7 @@ Released 2018-09-13
|
|||
[`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type
|
||||
[`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool
|
||||
[`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
|
||||
[`needless_bool_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool_assign
|
||||
[`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
|
||||
[`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference
|
||||
[`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy"
|
||||
version = "0.1.70"
|
||||
version = "0.1.71"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
|
|
@ -91,7 +91,8 @@ cargo clippy
|
|||
|
||||
#### Automatically applying Clippy suggestions
|
||||
|
||||
Clippy can automatically apply some lint suggestions, just like the compiler.
|
||||
Clippy can automatically apply some lint suggestions, just like the compiler. Note that `--fix` implies
|
||||
`--all-targets`, so it can fix as much code as it can.
|
||||
|
||||
```terminal
|
||||
cargo clippy --fix
|
||||
|
|
|
@ -50,7 +50,7 @@ questions already, but the parser is okay with it. This is what we
|
|||
mean when we say `EarlyLintPass` deals with only syntax on the AST level.
|
||||
|
||||
Alternatively, think of the `foo_functions` lint we mentioned in
|
||||
define new lints chapter.
|
||||
define new lints <!-- FIXME: add link --> chapter.
|
||||
|
||||
We want the `foo_functions` lint to detect functions with `foo` as their name.
|
||||
Writing a lint that only checks for the name of a function means that we only
|
||||
|
|
|
@ -139,7 +139,7 @@ whether the pattern matched.
|
|||
|
||||
## Pattern syntax
|
||||
|
||||
The following examples demonstate the pattern syntax:
|
||||
The following examples demonstrate the pattern syntax:
|
||||
|
||||
|
||||
#### Any (`_`)
|
||||
|
|
|
@ -13,6 +13,8 @@ Please use that command to update the file and do not edit it by hand.
|
|||
| [msrv](#msrv) | `None` |
|
||||
| [cognitive-complexity-threshold](#cognitive-complexity-threshold) | `25` |
|
||||
| [disallowed-names](#disallowed-names) | `["foo", "baz", "quux"]` |
|
||||
| [semicolon-inside-block-ignore-singleline](#semicolon-inside-block-ignore-singleline) | `false` |
|
||||
| [semicolon-outside-block-ignore-multiline](#semicolon-outside-block-ignore-multiline) | `false` |
|
||||
| [doc-valid-idents](#doc-valid-idents) | `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` |
|
||||
| [too-many-arguments-threshold](#too-many-arguments-threshold) | `7` |
|
||||
| [type-complexity-threshold](#type-complexity-threshold) | `250` |
|
||||
|
@ -203,6 +205,22 @@ default configuration of Clippy. By default, any configuration will replace the
|
|||
* [disallowed_names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names)
|
||||
|
||||
|
||||
### semicolon-inside-block-ignore-singleline
|
||||
Whether to lint only if it's multiline.
|
||||
|
||||
**Default Value:** `false` (`bool`)
|
||||
|
||||
* [semicolon_inside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block)
|
||||
|
||||
|
||||
### semicolon-outside-block-ignore-multiline
|
||||
Whether to lint only if it's singleline.
|
||||
|
||||
**Default Value:** `false` (`bool`)
|
||||
|
||||
* [semicolon_outside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block)
|
||||
|
||||
|
||||
### doc-valid-idents
|
||||
The list of words this lint should not consider as identifiers needing ticks. The value
|
||||
`".."` can be used as part of the list to indicate, that the configured values should be appended to the
|
||||
|
|
|
@ -111,7 +111,8 @@ fn main() {
|
|||
|
||||
### Automatically applying Clippy suggestions
|
||||
|
||||
Clippy can automatically apply some lint suggestions, just like the compiler.
|
||||
Clippy can automatically apply some lint suggestions, just like the compiler. Note that `--fix` implies
|
||||
`--all-targets`, so it can fix as much code as it can.
|
||||
|
||||
```terminal
|
||||
cargo clippy --fix
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::clippy_project_root;
|
||||
use crate::{clippy_project_root, exit_if_err};
|
||||
use std::process::Command;
|
||||
|
||||
/// # Panics
|
||||
|
@ -10,7 +10,7 @@ pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) {
|
|||
cmd.current_dir(clippy_project_root())
|
||||
.args(["test", "--test", "dogfood"])
|
||||
.args(["--features", "internal"])
|
||||
.args(["--", "dogfood_clippy"]);
|
||||
.args(["--", "dogfood_clippy", "--nocapture"]);
|
||||
|
||||
let mut dogfood_args = Vec::new();
|
||||
if fix {
|
||||
|
@ -27,7 +27,5 @@ pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) {
|
|||
|
||||
cmd.env("__CLIPPY_DOGFOOD_ARGS", dogfood_args.join(" "));
|
||||
|
||||
let output = cmd.output().expect("failed to run command");
|
||||
|
||||
println!("{}", String::from_utf8_lossy(&output.stdout));
|
||||
exit_if_err(cmd.status());
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
extern crate rustc_driver;
|
||||
extern crate rustc_lexer;
|
||||
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{self, ExitStatus};
|
||||
|
||||
pub mod bless;
|
||||
pub mod dogfood;
|
||||
|
@ -58,3 +60,14 @@ pub fn clippy_project_root() -> PathBuf {
|
|||
}
|
||||
panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
|
||||
}
|
||||
|
||||
pub fn exit_if_err(status: io::Result<ExitStatus>) {
|
||||
match status.expect("failed to run command").code() {
|
||||
Some(0) => {},
|
||||
Some(n) => process::exit(n),
|
||||
None => {
|
||||
eprintln!("Killed by signal");
|
||||
process::exit(1);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,6 @@
|
|||
use crate::cargo_clippy_path;
|
||||
use std::process::{self, Command, ExitStatus};
|
||||
use std::{fs, io};
|
||||
|
||||
fn exit_if_err(status: io::Result<ExitStatus>) {
|
||||
match status.expect("failed to run command").code() {
|
||||
Some(0) => {},
|
||||
Some(n) => process::exit(n),
|
||||
None => {
|
||||
eprintln!("Killed by signal");
|
||||
process::exit(1);
|
||||
},
|
||||
}
|
||||
}
|
||||
use crate::{cargo_clippy_path, exit_if_err};
|
||||
use std::fs;
|
||||
use std::process::{self, Command};
|
||||
|
||||
pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
|
||||
let is_file = match fs::metadata(path) {
|
||||
|
|
|
@ -36,60 +36,6 @@ pub enum UpdateMode {
|
|||
pub fn update(update_mode: UpdateMode) {
|
||||
let (lints, deprecated_lints, renamed_lints) = gather_all();
|
||||
generate_lint_files(update_mode, &lints, &deprecated_lints, &renamed_lints);
|
||||
remove_old_files(update_mode);
|
||||
}
|
||||
|
||||
/// Remove files no longer needed after <https://github.com/rust-lang/rust-clippy/pull/9541>
|
||||
/// that may be reintroduced unintentionally
|
||||
///
|
||||
/// FIXME: This is a temporary measure that should be removed when there are no more PRs that
|
||||
/// include the stray files
|
||||
fn remove_old_files(update_mode: UpdateMode) {
|
||||
let mut failed = false;
|
||||
let mut remove_file = |path: &Path| match update_mode {
|
||||
UpdateMode::Check => {
|
||||
if path.exists() {
|
||||
failed = true;
|
||||
println!("unexpected file: {}", path.display());
|
||||
}
|
||||
},
|
||||
UpdateMode::Change => {
|
||||
if fs::remove_file(path).is_ok() {
|
||||
println!("removed file: {}", path.display());
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let files = [
|
||||
"clippy_lints/src/lib.register_all.rs",
|
||||
"clippy_lints/src/lib.register_cargo.rs",
|
||||
"clippy_lints/src/lib.register_complexity.rs",
|
||||
"clippy_lints/src/lib.register_correctness.rs",
|
||||
"clippy_lints/src/lib.register_internal.rs",
|
||||
"clippy_lints/src/lib.register_lints.rs",
|
||||
"clippy_lints/src/lib.register_nursery.rs",
|
||||
"clippy_lints/src/lib.register_pedantic.rs",
|
||||
"clippy_lints/src/lib.register_perf.rs",
|
||||
"clippy_lints/src/lib.register_restriction.rs",
|
||||
"clippy_lints/src/lib.register_style.rs",
|
||||
"clippy_lints/src/lib.register_suspicious.rs",
|
||||
"src/docs.rs",
|
||||
];
|
||||
|
||||
for file in files {
|
||||
remove_file(Path::new(file));
|
||||
}
|
||||
|
||||
if let Ok(docs_dir) = fs::read_dir("src/docs") {
|
||||
for doc_file in docs_dir {
|
||||
let path = doc_file.unwrap().path();
|
||||
remove_file(&path);
|
||||
}
|
||||
}
|
||||
|
||||
if failed {
|
||||
exit_with_failure();
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_lint_files(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.70"
|
||||
version = "0.1.71"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
@ -20,7 +20,7 @@ quine-mc_cluskey = "0.2"
|
|||
regex-syntax = "0.6"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = { version = "1.0", optional = true }
|
||||
tempfile = { version = "3.2", optional = true }
|
||||
tempfile = { version = "3.3.0", optional = true }
|
||||
toml = "0.5"
|
||||
unicode-normalization = "0.1"
|
||||
unicode-script = { version = "0.5", default-features = false }
|
||||
|
|
|
@ -2,7 +2,8 @@ use ast::AttrStyle;
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use rustc_ast as ast;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
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! {
|
||||
|
@ -51,6 +52,7 @@ impl LateLintPass<'_> for AllowAttribute {
|
|||
// Separate each crate's features.
|
||||
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
|
||||
if_chain! {
|
||||
if !in_external_macro(cx.sess(), attr.span);
|
||||
if cx.tcx.features().lint_reasons;
|
||||
if let AttrStyle::Outer = attr.style;
|
||||
if let Some(ident) = attr.ident();
|
||||
|
|
|
@ -85,8 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
let span =
|
||||
block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
|
||||
let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
|
||||
if span.from_expansion() || expr.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -638,7 +638,7 @@ declare_clippy_lint! {
|
|||
#[clippy::version = "1.66.0"]
|
||||
pub AS_PTR_CAST_MUT,
|
||||
nursery,
|
||||
"casting the result of the `&self`-taking `as_ptr` to a mutabe pointer"
|
||||
"casting the result of the `&self`-taking `as_ptr` to a mutable pointer"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
|
|
@ -141,9 +141,9 @@ fn lint_unnecessary_cast(
|
|||
|
||||
fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
|
||||
match expr.kind {
|
||||
ExprKind::Lit(ref lit) => Some(lit),
|
||||
ExprKind::Lit(lit) => Some(lit),
|
||||
ExprKind::Unary(UnOp::Neg, e) => {
|
||||
if let ExprKind::Lit(ref lit) = e.kind {
|
||||
if let ExprKind::Lit(lit) = e.kind {
|
||||
Some(lit)
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -591,7 +591,7 @@ fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &De
|
|||
conds,
|
||||
|e| hash_expr(cx, e),
|
||||
|lhs, rhs| {
|
||||
// Ignore eq_expr side effects iff one of the expressin kind is a method call
|
||||
// Ignore eq_expr side effects iff one of the expression kind is a method call
|
||||
// and the caller is not a mutable, including inner mutable type.
|
||||
if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind {
|
||||
if method_caller_is_mutable(cx, caller, ignored_ty_ids) {
|
||||
|
|
|
@ -105,6 +105,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::dbg_macro::DBG_MACRO_INFO,
|
||||
crate::default::DEFAULT_TRAIT_ACCESS_INFO,
|
||||
crate::default::FIELD_REASSIGN_WITH_DEFAULT_INFO,
|
||||
crate::default_constructed_unit_structs::DEFAULT_CONSTRUCTED_UNIT_STRUCTS_INFO,
|
||||
crate::default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY_INFO,
|
||||
crate::default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK_INFO,
|
||||
crate::default_union_representation::DEFAULT_UNION_REPRESENTATION_INFO,
|
||||
|
@ -249,6 +250,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::loops::MANUAL_FIND_INFO,
|
||||
crate::loops::MANUAL_FLATTEN_INFO,
|
||||
crate::loops::MANUAL_MEMCPY_INFO,
|
||||
crate::loops::MANUAL_WHILE_LET_SOME_INFO,
|
||||
crate::loops::MISSING_SPIN_LOOP_INFO,
|
||||
crate::loops::MUT_RANGE_BOUND_INFO,
|
||||
crate::loops::NEEDLESS_RANGE_LOOP_INFO,
|
||||
|
@ -445,6 +447,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO,
|
||||
crate::needless_bool::BOOL_COMPARISON_INFO,
|
||||
crate::needless_bool::NEEDLESS_BOOL_INFO,
|
||||
crate::needless_bool::NEEDLESS_BOOL_ASSIGN_INFO,
|
||||
crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO,
|
||||
crate::needless_continue::NEEDLESS_CONTINUE_INFO,
|
||||
crate::needless_for_each::NEEDLESS_FOR_EACH_INFO,
|
||||
|
|
72
clippy_lints/src/default_constructed_unit_structs.rs
Normal file
72
clippy_lints/src/default_constructed_unit_structs.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro, match_def_path, paths};
|
||||
use hir::{def::Res, ExprKind};
|
||||
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! {
|
||||
/// ### What it does
|
||||
/// Check for construction on unit struct using `default`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// This adds code complexity and an unnecessary function call.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # use std::marker::PhantomData;
|
||||
/// #[derive(Default)]
|
||||
/// struct S<T> {
|
||||
/// _marker: PhantomData<T>
|
||||
/// }
|
||||
///
|
||||
/// let _: S<i32> = S {
|
||||
/// _marker: PhantomData::default()
|
||||
/// };
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # use std::marker::PhantomData;
|
||||
/// struct S<T> {
|
||||
/// _marker: PhantomData<T>
|
||||
/// }
|
||||
///
|
||||
/// let _: S<i32> = S {
|
||||
/// _marker: PhantomData
|
||||
/// };
|
||||
/// ```
|
||||
#[clippy::version = "1.71.0"]
|
||||
pub DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
|
||||
complexity,
|
||||
"unit structs can be contructed without calling `default`"
|
||||
}
|
||||
declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]);
|
||||
|
||||
impl LateLintPass<'_> for DefaultConstructedUnitStructs {
|
||||
fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||
if_chain!(
|
||||
// make sure we have a call to `Default::default`
|
||||
if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind;
|
||||
if let ExprKind::Path(ref qpath@ hir::QPath::TypeRelative(_,_)) = fn_expr.kind;
|
||||
if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
|
||||
if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
|
||||
// make sure we have a struct with no fields (unit struct)
|
||||
if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind();
|
||||
if def.is_struct();
|
||||
if let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant();
|
||||
if !var.is_field_list_non_exhaustive() && !is_from_proc_macro(cx, expr);
|
||||
then {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
|
||||
expr.span.with_lo(qpath.qself_span().hi()),
|
||||
"use of `default` to create a unit struct",
|
||||
"remove this call to `default`",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -92,10 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
|
|||
if trait_item.id.owner_id.def_id == fn_def_id {
|
||||
// be sure we have `self` parameter in this function
|
||||
if trait_item.kind == (AssocItemKind::Fn { has_self: true }) {
|
||||
trait_self_ty = Some(
|
||||
TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id())
|
||||
.self_ty(),
|
||||
);
|
||||
trait_self_ty =
|
||||
Some(TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id()).self_ty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
|
|||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
if_chain! {
|
||||
if let ty::Float(fty) = *ty.kind();
|
||||
if let hir::ExprKind::Lit(ref lit) = expr.kind;
|
||||
if let hir::ExprKind::Lit(lit) = expr.kind;
|
||||
if let LitKind::Float(sym, lit_float_ty) = lit.node;
|
||||
then {
|
||||
let sym_str = sym.as_str();
|
||||
|
|
|
@ -2,9 +2,10 @@ use clippy_utils::consts::{
|
|||
constant, constant_simple, Constant,
|
||||
Constant::{Int, F32, F64},
|
||||
};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, peel_blocks, sugg};
|
||||
use clippy_utils::{
|
||||
diagnostics::span_lint_and_sugg, eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate,
|
||||
numeric_literal, peel_blocks, sugg,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
|
||||
|
@ -677,7 +678,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||
{
|
||||
let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
|
||||
if_chain! {
|
||||
if let ExprKind::Lit(ref literal) = mul_lhs.kind;
|
||||
if let ExprKind::Lit(literal) = mul_lhs.kind;
|
||||
if let ast::LitKind::Float(ref value, float_type) = literal.node;
|
||||
if float_type == ast::LitFloatType::Unsuffixed;
|
||||
then {
|
||||
|
@ -703,7 +704,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||
{
|
||||
let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
|
||||
if_chain! {
|
||||
if let ExprKind::Lit(ref literal) = mul_lhs.kind;
|
||||
if let ExprKind::Lit(literal) = mul_lhs.kind;
|
||||
if let ast::LitKind::Float(ref value, float_type) = literal.node;
|
||||
if float_type == ast::LitFloatType::Unsuffixed;
|
||||
then {
|
||||
|
@ -730,7 +731,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
// All of these operations are currently not const.
|
||||
// All of these operations are currently not const and are in std.
|
||||
if in_constant(cx, expr.hir_id) {
|
||||
return;
|
||||
}
|
||||
|
@ -738,7 +739,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
|
|||
if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
|
||||
let recv_ty = cx.typeck_results().expr_ty(receiver);
|
||||
|
||||
if recv_ty.is_floating_point() {
|
||||
if recv_ty.is_floating_point() && !is_no_std_crate(cx) {
|
||||
match path.ident.name.as_str() {
|
||||
"ln" => check_ln1p(cx, expr, receiver),
|
||||
"log" => check_log_base(cx, expr, receiver, args),
|
||||
|
@ -749,10 +750,12 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
check_expm1(cx, expr);
|
||||
check_mul_add(cx, expr);
|
||||
check_custom_abs(cx, expr);
|
||||
check_log_division(cx, expr);
|
||||
if !is_no_std_crate(cx) {
|
||||
check_expm1(cx, expr);
|
||||
check_mul_add(cx, expr);
|
||||
check_custom_abs(cx, expr);
|
||||
check_log_division(cx, expr);
|
||||
}
|
||||
check_radians(cx, expr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
|
|||
);
|
||||
}
|
||||
|
||||
let message = format!("replace the `Into` implentation with `From<{}>`", middle_trait_ref.self_ty());
|
||||
let message = format!("replace the `Into` implementation with `From<{}>`", middle_trait_ref.self_ty());
|
||||
if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) {
|
||||
diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable);
|
||||
} else {
|
||||
|
|
|
@ -40,7 +40,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
|
|||
};
|
||||
|
||||
// Body must be &(mut) <self_data>.name
|
||||
// self_data is not neccessarilly self, to also lint sub-getters, etc…
|
||||
// self_data is not necessarily self, to also lint sub-getters, etc…
|
||||
|
||||
let block_expr = if_chain! {
|
||||
if let ExprKind::Block(block,_) = body.value.kind;
|
||||
|
|
|
@ -252,6 +252,11 @@ declare_clippy_lint! {
|
|||
/// A `Result` is at least as large as the `Err`-variant. While we
|
||||
/// expect that variant to be seldomly used, the compiler needs to reserve
|
||||
/// and move that much memory every single time.
|
||||
/// Furthermore, errors are often simply passed up the call-stack, making
|
||||
/// use of the `?`-operator and its type-conversion mechanics. If the
|
||||
/// `Err`-variant further up the call-stack stores the `Err`-variant in
|
||||
/// question (as library code often does), it itself needs to be at least
|
||||
/// as large, propagating the problem.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// The size determined by Clippy is platform-dependent.
|
||||
|
@ -330,7 +335,7 @@ declare_clippy_lint! {
|
|||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Lints when `impl Trait` is being used in a function's paremeters.
|
||||
/// Lints when `impl Trait` is being used in a function's parameters.
|
||||
/// ### Why is this bad?
|
||||
/// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor.
|
||||
///
|
||||
|
|
|
@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
|
|||
if expr1.span.ctxt() == ctxt;
|
||||
if clippy_utils::SpanlessEq::new(cx).eq_expr(l, target);
|
||||
if BinOpKind::Add == op1.node;
|
||||
if let ExprKind::Lit(ref lit) = value.kind;
|
||||
if let ExprKind::Lit(lit) = value.kind;
|
||||
if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
|
||||
if block.expr.is_none();
|
||||
then {
|
||||
|
|
|
@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
|
|||
// Get the variable name
|
||||
let var_name = ares_path.segments[0].ident.name.as_str();
|
||||
match cond_num_val.kind {
|
||||
ExprKind::Lit(ref cond_lit) => {
|
||||
ExprKind::Lit(cond_lit) => {
|
||||
// Check if the constant is zero
|
||||
if let LitKind::Int(0, _) = cond_lit.node {
|
||||
if cx.typeck_results().expr_ty(cond_left).is_signed() {
|
||||
|
|
|
@ -170,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
|
|||
return;
|
||||
}
|
||||
// Index is a constant uint.
|
||||
if let Some(..) = constant(cx, cx.typeck_results(), index) {
|
||||
if constant(cx, cx.typeck_results(), index).is_some() {
|
||||
// Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -64,20 +64,21 @@ impl LateLintPass<'_> for ItemsAfterTestModule {
|
|||
span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined");
|
||||
}};
|
||||
|
||||
if matches!(item.kind, ItemKind::Mod(_)) {
|
||||
for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
|
||||
if_chain! {
|
||||
if attr.has_name(sym::cfg);
|
||||
if let ItemKind::Mod(module) = item.kind && item.span.hi() == module.spans.inner_span.hi() {
|
||||
// Check that it works the same way, the only I way I've found for #10713
|
||||
for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
|
||||
if_chain! {
|
||||
if attr.has_name(sym::cfg);
|
||||
if let Some(mitems) = attr.meta_item_list();
|
||||
if let [mitem] = &*mitems;
|
||||
if mitem.has_name(sym::test);
|
||||
then {
|
||||
was_test_mod_visited = true;
|
||||
was_test_mod_visited = true;
|
||||
test_mod_span = Some(item.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ declare_clippy_lint! {
|
|||
/// It checks for the size of a `Future` created by `async fn` or `async {}`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Due to the current [unideal implemention](https://github.com/rust-lang/rust/issues/69826) of `Generator`,
|
||||
/// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Generator`,
|
||||
/// large size of a `Future` may cause stack overflows.
|
||||
///
|
||||
/// ### Example
|
||||
|
|
|
@ -532,7 +532,7 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex
|
|||
}
|
||||
|
||||
fn is_empty_string(expr: &Expr<'_>) -> bool {
|
||||
if let ExprKind::Lit(ref lit) = expr.kind {
|
||||
if let ExprKind::Lit(lit) = expr.kind {
|
||||
if let LitKind::Str(lit, _) = lit.node {
|
||||
let lit = lit.as_str();
|
||||
return lit.is_empty();
|
||||
|
|
|
@ -6,6 +6,7 @@ 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 rustc_span::{BytePos, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -205,8 +206,13 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
|
|||
LET_UNDERSCORE_UNTYPED,
|
||||
local.span,
|
||||
"non-binding `let` without a type annotation",
|
||||
None,
|
||||
"consider adding a type annotation or removing the `let` keyword",
|
||||
Some(
|
||||
Span::new(local.pat.span.hi(),
|
||||
local.pat.span.hi() + BytePos(1),
|
||||
local.pat.span.ctxt(),
|
||||
local.pat.span.parent()
|
||||
)),
|
||||
"consider adding a type annotation",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,6 +94,7 @@ mod crate_in_macro_def;
|
|||
mod create_dir;
|
||||
mod dbg_macro;
|
||||
mod default;
|
||||
mod default_constructed_unit_structs;
|
||||
mod default_instead_of_iter_empty;
|
||||
mod default_numeric_fallback;
|
||||
mod default_union_representation;
|
||||
|
@ -933,7 +934,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
|
||||
store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
|
||||
store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
|
||||
store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
|
||||
let semicolon_inside_block_ignore_singleline = conf.semicolon_inside_block_ignore_singleline;
|
||||
let semicolon_outside_block_ignore_multiline = conf.semicolon_outside_block_ignore_multiline;
|
||||
store.register_late_pass(move |_| {
|
||||
Box::new(semicolon_block::SemicolonBlock::new(
|
||||
semicolon_inside_block_ignore_singleline,
|
||||
semicolon_outside_block_ignore_multiline,
|
||||
))
|
||||
});
|
||||
store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
|
||||
store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
|
||||
store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
|
||||
|
@ -963,6 +971,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
|
||||
store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments));
|
||||
store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
|
||||
store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ use rustc_span::symbol::sym;
|
|||
use std::fmt::Display;
|
||||
use std::iter::Iterator;
|
||||
|
||||
/// Checks for for loops that sequentially copy items from one slice-like
|
||||
/// Checks for `for` loops that sequentially copy items from one slice-like
|
||||
/// object to another.
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
|
|
110
clippy_lints/src/loops/manual_while_let_some.rs
Normal file
110
clippy_lints/src/loops/manual_while_let_some.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
use clippy_utils::{
|
||||
diagnostics::{multispan_sugg_with_applicability, span_lint_and_then},
|
||||
match_def_path, paths,
|
||||
source::snippet,
|
||||
SpanlessEq,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::Span;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::MANUAL_WHILE_LET_SOME;
|
||||
|
||||
/// The kind of statement that the `pop()` call appeared in.
|
||||
///
|
||||
/// Depending on whether the value was assigned to a variable or not changes what pattern
|
||||
/// we use for the suggestion.
|
||||
#[derive(Copy, Clone)]
|
||||
enum PopStmt<'hir> {
|
||||
/// `x.pop().unwrap()` was and assigned to a variable.
|
||||
/// The pattern of this local variable will be used and the local statement
|
||||
/// is deleted in the suggestion.
|
||||
Local(&'hir Pat<'hir>),
|
||||
/// `x.pop().unwrap()` appeared in an arbitrary expression and was not assigned to a variable.
|
||||
/// The suggestion will use some placeholder identifier and the `x.pop().unwrap()` expression
|
||||
/// is replaced with that identifier.
|
||||
Anonymous,
|
||||
}
|
||||
|
||||
fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>, loop_span: Span, receiver_span: Span) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_WHILE_LET_SOME,
|
||||
pop_span,
|
||||
"you seem to be trying to pop elements from a `Vec` in a loop",
|
||||
|diag| {
|
||||
let (pat, pop_replacement) = match pop_stmt_kind {
|
||||
PopStmt::Local(pat) => (snippet(cx, pat.span, ".."), String::new()),
|
||||
PopStmt::Anonymous => (Cow::Borrowed("element"), "element".into()),
|
||||
};
|
||||
|
||||
let loop_replacement = format!("while let Some({}) = {}.pop()", pat, snippet(cx, receiver_span, ".."));
|
||||
multispan_sugg_with_applicability(
|
||||
diag,
|
||||
"consider using a `while..let` loop",
|
||||
Applicability::MachineApplicable,
|
||||
[(loop_span, loop_replacement), (pop_span, pop_replacement)],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: &[&str]) -> bool {
|
||||
if let ExprKind::MethodCall(..) = expr.kind
|
||||
&& let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
|
||||
{
|
||||
match_def_path(cx, id, method)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, is_empty_recv: &Expr<'_>) -> bool {
|
||||
if (match_method_call(cx, expr, &paths::OPTION_UNWRAP) || match_method_call(cx, expr, &paths::OPTION_EXPECT))
|
||||
&& let ExprKind::MethodCall(_, unwrap_recv, ..) = expr.kind
|
||||
&& match_method_call(cx, unwrap_recv, &paths::VEC_POP)
|
||||
&& let ExprKind::MethodCall(_, pop_recv, ..) = unwrap_recv.kind
|
||||
{
|
||||
// make sure they're the same `Vec`
|
||||
SpanlessEq::new(cx).eq_expr(pop_recv, is_empty_recv)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) {
|
||||
if let StmtKind::Local(local) = stmt.kind
|
||||
&& let Some(init) = local.init
|
||||
&& is_vec_pop_unwrap(cx, init, is_empty_recv)
|
||||
{
|
||||
report_lint(cx, stmt.span, PopStmt::Local(local.pat), loop_span, is_empty_recv.span);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) {
|
||||
if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind {
|
||||
if let ExprKind::MethodCall(.., args, _) | ExprKind::Call(_, args) = expr.kind {
|
||||
let offending_arg = args
|
||||
.iter()
|
||||
.find_map(|arg| is_vec_pop_unwrap(cx, arg, is_empty_recv).then_some(arg.span));
|
||||
|
||||
if let Some(offending_arg) = offending_arg {
|
||||
report_lint(cx, offending_arg, PopStmt::Anonymous, loop_span, is_empty_recv.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, full_cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>, loop_span: Span) {
|
||||
if let ExprKind::Unary(UnOp::Not, cond) = full_cond.kind
|
||||
&& let ExprKind::MethodCall(_, is_empty_recv, _, _) = cond.kind
|
||||
&& match_method_call(cx, cond, &paths::VEC_IS_EMPTY)
|
||||
&& let ExprKind::Block(body, _) = body.kind
|
||||
&& let Some(stmt) = body.stmts.first()
|
||||
{
|
||||
check_local(cx, stmt, is_empty_recv, loop_span);
|
||||
check_call_arguments(cx, stmt, is_empty_recv, loop_span);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ mod iter_next_loop;
|
|||
mod manual_find;
|
||||
mod manual_flatten;
|
||||
mod manual_memcpy;
|
||||
mod manual_while_let_some;
|
||||
mod missing_spin_loop;
|
||||
mod mut_range_bound;
|
||||
mod needless_range_loop;
|
||||
|
@ -575,6 +576,36 @@ declare_clippy_lint! {
|
|||
"manual implementation of `Iterator::find`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Looks for loops that check for emptiness of a `Vec` in the condition and pop an element
|
||||
/// in the body as a separate operation.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Such loops can be written in a more idiomatic way by using a while-let loop and directly
|
||||
/// pattern matching on the return value of `Vec::pop()`.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let mut numbers = vec![1, 2, 3, 4, 5];
|
||||
/// while !numbers.is_empty() {
|
||||
/// let number = numbers.pop().unwrap();
|
||||
/// // use `number`
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let mut numbers = vec![1, 2, 3, 4, 5];
|
||||
/// while let Some(number) = numbers.pop() {
|
||||
/// // use `number`
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.70.0"]
|
||||
pub MANUAL_WHILE_LET_SOME,
|
||||
style,
|
||||
"checking for emptiness of a `Vec` in the loop condition and popping an element in the body"
|
||||
}
|
||||
|
||||
declare_lint_pass!(Loops => [
|
||||
MANUAL_MEMCPY,
|
||||
MANUAL_FLATTEN,
|
||||
|
@ -594,6 +625,7 @@ declare_lint_pass!(Loops => [
|
|||
SINGLE_ELEMENT_LOOP,
|
||||
MISSING_SPIN_LOOP,
|
||||
MANUAL_FIND,
|
||||
MANUAL_WHILE_LET_SOME
|
||||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Loops {
|
||||
|
@ -640,9 +672,10 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
|
|||
|
||||
while_let_on_iterator::check(cx, expr);
|
||||
|
||||
if let Some(higher::While { condition, body }) = higher::While::hir(expr) {
|
||||
if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) {
|
||||
while_immutable_condition::check(cx, condition, body);
|
||||
missing_spin_loop::check(cx, condition, body);
|
||||
manual_while_let_some::check(cx, condition, body, span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,7 +208,7 @@ fn is_end_eq_array_len<'tcx>(
|
|||
indexed_ty: Ty<'tcx>,
|
||||
) -> bool {
|
||||
if_chain! {
|
||||
if let ExprKind::Lit(ref lit) = end.kind;
|
||||
if let ExprKind::Lit(lit) = end.kind;
|
||||
if let ast::LitKind::Int(end_int, _) = lit.node;
|
||||
if let ty::Array(_, arr_len_const) = indexed_ty.kind();
|
||||
if let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env);
|
||||
|
|
|
@ -35,7 +35,8 @@ struct PathAndSpan {
|
|||
span: Span,
|
||||
}
|
||||
|
||||
/// `MacroRefData` includes the name of the macro.
|
||||
/// `MacroRefData` includes the name of the macro
|
||||
/// and the path from `SourceMap::span_to_filename`.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MacroRefData {
|
||||
name: String,
|
||||
|
|
|
@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
|
|||
};
|
||||
let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
|
||||
let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
|
||||
// we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block
|
||||
// we show to the user the suggestion without the comments, but when applying the fix, include the comments in the block
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_ASSERT,
|
||||
|
|
|
@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
|
|||
if source != MatchSource::Normal {
|
||||
return;
|
||||
}
|
||||
// Any other number than two arms doesn't (neccessarily)
|
||||
// Any other number than two arms doesn't (necessarily)
|
||||
// have a trivial mapping to let else.
|
||||
if arms.len() != 2 {
|
||||
return;
|
||||
|
|
|
@ -46,7 +46,7 @@ declare_clippy_lint! {
|
|||
#[clippy::version = "1.64.0"]
|
||||
pub MANUAL_RETAIN,
|
||||
perf,
|
||||
"`retain()` is simpler and the same functionalitys"
|
||||
"`retain()` is simpler and the same functionalities"
|
||||
}
|
||||
|
||||
pub struct ManualRetain {
|
||||
|
|
|
@ -22,7 +22,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
|
|||
if arms.len() == 2 {
|
||||
// no guards
|
||||
let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
|
||||
if let ExprKind::Lit(ref lit) = arm_bool.kind {
|
||||
if let ExprKind::Lit(lit) = arm_bool.kind {
|
||||
match lit.node {
|
||||
LitKind::Bool(true) => Some((arms[0].body, arms[1].body)),
|
||||
LitKind::Bool(false) => Some((arms[1].body, arms[0].body)),
|
||||
|
|
|
@ -63,8 +63,11 @@ fn find_sugg_for_if_let<'tcx>(
|
|||
// Determine which function should be used, and the type contained by the corresponding
|
||||
// variant.
|
||||
let (good_method, inner_ty) = match check_pat.kind {
|
||||
PatKind::TupleStruct(ref qpath, [sub_pat], _) => {
|
||||
if let PatKind::Wild = sub_pat.kind {
|
||||
PatKind::TupleStruct(ref qpath, args, rest) => {
|
||||
let is_wildcard = matches!(args.first().map(|p| &p.kind), Some(PatKind::Wild));
|
||||
let is_rest = matches!((args, rest.as_opt_usize()), ([], Some(_)));
|
||||
|
||||
if is_wildcard || is_rest {
|
||||
let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
|
||||
let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
|
||||
let lang_items = cx.tcx.lang_items();
|
||||
|
@ -334,7 +337,7 @@ fn find_good_method_for_match<'a>(
|
|||
};
|
||||
|
||||
match body_node_pair {
|
||||
(ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
|
||||
(ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) {
|
||||
(LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
|
||||
(LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
|
||||
_ => None,
|
||||
|
|
|
@ -18,7 +18,7 @@ pub(super) fn check(
|
|||
) -> bool {
|
||||
if_chain! {
|
||||
if let Some(args) = method_chain_args(info.chain, chain_methods);
|
||||
if let hir::ExprKind::Lit(ref lit) = info.other.kind;
|
||||
if let hir::ExprKind::Lit(lit) = info.other.kind;
|
||||
if let ast::LitKind::Char(c) = lit.node;
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
|
|
@ -7,7 +7,7 @@ use rustc_errors::Applicability;
|
|||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::symbol::{Symbol, sym};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
use super::INEFFICIENT_TO_STRING;
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
|
|||
if let hir::ExprKind::Index(caller_var, index_expr) = &caller_expr.kind;
|
||||
if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
|
||||
= higher::Range::hir(index_expr);
|
||||
if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
|
||||
if let hir::ExprKind::Lit(start_lit) = &start_expr.kind;
|
||||
if let ast::LitKind::Int(start_idx, _) = start_lit.node;
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
|
|
@ -42,11 +42,11 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
|
|||
// Only proceed if this is a call on some object of type std::fs::OpenOptions
|
||||
if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && !arguments.is_empty() {
|
||||
let argument_option = match arguments[0].kind {
|
||||
ExprKind::Lit(ref span) => {
|
||||
ExprKind::Lit(span) => {
|
||||
if let Spanned {
|
||||
node: LitKind::Bool(lit),
|
||||
..
|
||||
} = *span
|
||||
} = span
|
||||
{
|
||||
if *lit { Argument::True } else { Argument::False }
|
||||
} else {
|
||||
|
|
|
@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
|
|||
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
|
||||
if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
|
||||
if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::PathBuf);
|
||||
if let ExprKind::Lit(ref lit) = arg.kind;
|
||||
if let ExprKind::Lit(lit) = arg.kind;
|
||||
if let LitKind::Str(ref path_lit, _) = lit.node;
|
||||
if let pushed_path = Path::new(path_lit.as_str());
|
||||
if let Some(pushed_path_lit) = pushed_path.to_str();
|
||||
|
|
|
@ -38,7 +38,7 @@ fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)
|
|||
match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) {
|
||||
// check if argument of `SeekFrom::Current` is `0`
|
||||
if args.len() == 1 &&
|
||||
let ExprKind::Lit(ref lit) = args[0].kind &&
|
||||
let ExprKind::Lit(lit) = args[0].kind &&
|
||||
let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
|
|||
let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() &&
|
||||
match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) &&
|
||||
args1.len() == 1 &&
|
||||
let ExprKind::Lit(ref lit) = args1[0].kind &&
|
||||
let ExprKind::Lit(lit) = args1[0].kind &&
|
||||
let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
|
||||
{
|
||||
let method_call_span = expr.span.with_lo(name_span.lo());
|
||||
|
|
|
@ -78,7 +78,7 @@ pub(super) fn check(
|
|||
}
|
||||
|
||||
// Check if the first argument to .fold is a suitable literal
|
||||
if let hir::ExprKind::Lit(ref lit) = init.kind {
|
||||
if let hir::ExprKind::Lit(lit) = init.kind {
|
||||
match lit.node {
|
||||
ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, "any", true),
|
||||
ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true),
|
||||
|
|
|
@ -12,7 +12,7 @@ declare_clippy_lint! {
|
|||
/// Checks if a provided method is used implicitly by a trait
|
||||
/// implementation. A usage example would be a wrapper where every method
|
||||
/// should perform some operation before delegating to the inner type's
|
||||
/// implemenation.
|
||||
/// implementation.
|
||||
///
|
||||
/// This lint should typically be enabled on a specific trait `impl` item
|
||||
/// rather than globally.
|
||||
|
|
|
@ -92,10 +92,6 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
|
|||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::If(..) => {
|
||||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::Path(_) => {
|
||||
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
|
||||
if adj
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
//! This lint is **warn** by default
|
||||
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt};
|
||||
use clippy_utils::{
|
||||
get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment,
|
||||
};
|
||||
use clippy_utils::{higher, SpanlessEq};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp};
|
||||
|
@ -77,7 +79,39 @@ declare_clippy_lint! {
|
|||
"comparing a variable to a boolean, e.g., `if x == true` or `if x != true`"
|
||||
}
|
||||
|
||||
declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]);
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for expressions of the form `if c { x = true } else { x = false }`
|
||||
/// (or vice versa) and suggest assigning the variable directly from the
|
||||
/// condition.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Redundant code.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust,ignore
|
||||
/// # fn must_keep(x: i32, y: i32) -> bool { x == y }
|
||||
/// # let x = 32; let y = 10;
|
||||
/// # let mut skip: bool;
|
||||
/// if must_keep(x, y) {
|
||||
/// skip = false;
|
||||
/// } else {
|
||||
/// skip = true;
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust,ignore
|
||||
/// # fn must_keep(x: i32, y: i32) -> bool { x == y }
|
||||
/// # let x = 32; let y = 10;
|
||||
/// # let mut skip: bool;
|
||||
/// skip = !must_keep(x, y);
|
||||
/// ```
|
||||
#[clippy::version = "1.69.0"]
|
||||
pub NEEDLESS_BOOL_ASSIGN,
|
||||
complexity,
|
||||
"setting the same boolean variable in both branches of an if-statement"
|
||||
}
|
||||
declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL, NEEDLESS_BOOL_ASSIGN]);
|
||||
|
||||
fn condition_needs_parentheses(e: &Expr<'_>) -> bool {
|
||||
let mut inner = e;
|
||||
|
@ -173,6 +207,29 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
|
|||
_ => (),
|
||||
}
|
||||
}
|
||||
if let Some((lhs_a, a)) = fetch_assign(then) &&
|
||||
let Some((lhs_b, b)) = fetch_assign(r#else) &&
|
||||
SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) &&
|
||||
span_extract_comment(cx.tcx.sess.source_map(), e.span).is_empty()
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
|
||||
let lhs = snippet_with_applicability(cx, lhs_a.span, "..", &mut applicability);
|
||||
let sugg = if a == b {
|
||||
format!("{cond}; {lhs} = {a:?};")
|
||||
} else {
|
||||
format!("{lhs} = {};", if a { cond } else { !cond })
|
||||
};
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
NEEDLESS_BOOL_ASSIGN,
|
||||
e.span,
|
||||
"this if-then-else expression assigns a bool literal",
|
||||
"you can reduce it to",
|
||||
sugg,
|
||||
applicability
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -369,10 +426,18 @@ fn fetch_bool_block(expr: &Expr<'_>) -> Option<Expression> {
|
|||
}
|
||||
|
||||
fn fetch_bool_expr(expr: &Expr<'_>) -> Option<bool> {
|
||||
if let ExprKind::Lit(ref lit_ptr) = peel_blocks(expr).kind {
|
||||
if let ExprKind::Lit(lit_ptr) = peel_blocks(expr).kind {
|
||||
if let LitKind::Bool(value) = lit_ptr.node {
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn fetch_assign<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, bool)> {
|
||||
if let ExprKind::Assign(lhs, rhs, _) = peel_blocks_with_stmt(expr).kind {
|
||||
fetch_bool_expr(rhs).map(|b| (lhs, b))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,14 +49,14 @@ fn snippet_enclosed_in_parenthesis(snippet: &str) -> bool {
|
|||
|
||||
fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) {
|
||||
if is_start &&
|
||||
let ExprKind::Lit(ref literal) = e.kind &&
|
||||
let ExprKind::Lit(literal) = e.kind &&
|
||||
let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node
|
||||
{
|
||||
// don't check floating point literals on the start expression of a range
|
||||
return;
|
||||
}
|
||||
if_chain! {
|
||||
if let ExprKind::Lit(ref literal) = e.kind;
|
||||
if let ExprKind::Lit(literal) = e.kind;
|
||||
// the indicator that parenthesis surround the literal is that the span of the expression and the literal differ
|
||||
if (literal.span.data().hi - literal.span.data().lo) != (e.span.data().hi - e.span.data().lo);
|
||||
// inspect the source code of the expression for parenthesis
|
||||
|
|
|
@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for NegMultiply {
|
|||
|
||||
fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
|
||||
if_chain! {
|
||||
if let ExprKind::Lit(ref l) = lit.kind;
|
||||
if let ExprKind::Lit(l) = lit.kind;
|
||||
if consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1);
|
||||
if cx.typeck_results().expr_ty(exp).is_integral();
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ impl ArithmeticSideEffects {
|
|||
/// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`,
|
||||
fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> {
|
||||
let actual = peel_hir_expr_unary(expr).0;
|
||||
if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
|
||||
if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
|
||||
return Some(n)
|
||||
}
|
||||
if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) {
|
||||
|
|
|
@ -180,7 +180,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
|
|||
.allow_invalid_utf8(!utf8)
|
||||
.build();
|
||||
|
||||
if let ExprKind::Lit(ref lit) = expr.kind {
|
||||
if let ExprKind::Lit(lit) = expr.kind {
|
||||
if let LitKind::Str(ref r, style) = lit.node {
|
||||
let r = r.as_str();
|
||||
let offset = if let StrStyle::Raw(n) = style { 2 + n } else { 1 };
|
||||
|
|
|
@ -55,11 +55,11 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
|
|||
if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl { .. })
|
||||
&& let item = cx.tcx.hir().item(id)
|
||||
&& let ItemKind::Impl(Impl {
|
||||
items,
|
||||
of_trait,
|
||||
self_ty,
|
||||
..
|
||||
}) = &item.kind
|
||||
items,
|
||||
of_trait,
|
||||
self_ty,
|
||||
..
|
||||
}) = &item.kind
|
||||
&& let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
|
||||
{
|
||||
if !map.contains_key(res) {
|
||||
|
|
|
@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
@ -64,7 +64,78 @@ declare_clippy_lint! {
|
|||
restriction,
|
||||
"add a semicolon outside the block"
|
||||
}
|
||||
declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
|
||||
impl_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SemicolonBlock {
|
||||
semicolon_inside_block_ignore_singleline: bool,
|
||||
semicolon_outside_block_ignore_multiline: bool,
|
||||
}
|
||||
|
||||
impl SemicolonBlock {
|
||||
pub fn new(semicolon_inside_block_ignore_singleline: bool, semicolon_outside_block_ignore_multiline: bool) -> Self {
|
||||
Self {
|
||||
semicolon_inside_block_ignore_singleline,
|
||||
semicolon_outside_block_ignore_multiline,
|
||||
}
|
||||
}
|
||||
|
||||
fn semicolon_inside_block(self, cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
|
||||
let insert_span = tail.span.source_callsite().shrink_to_hi();
|
||||
let remove_span = semi_span.with_lo(block.span.hi());
|
||||
|
||||
if self.semicolon_inside_block_ignore_singleline && get_line(cx, remove_span) == get_line(cx, insert_span) {
|
||||
return;
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
SEMICOLON_INSIDE_BLOCK,
|
||||
semi_span,
|
||||
"consider moving the `;` inside the block for consistent formatting",
|
||||
|diag| {
|
||||
multispan_sugg_with_applicability(
|
||||
diag,
|
||||
"put the `;` here",
|
||||
Applicability::MachineApplicable,
|
||||
[(remove_span, String::new()), (insert_span, ";".to_owned())],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn semicolon_outside_block(
|
||||
self,
|
||||
cx: &LateContext<'_>,
|
||||
block: &Block<'_>,
|
||||
tail_stmt_expr: &Expr<'_>,
|
||||
semi_span: Span,
|
||||
) {
|
||||
let insert_span = block.span.with_lo(block.span.hi());
|
||||
// account for macro calls
|
||||
let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
|
||||
let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
|
||||
|
||||
if self.semicolon_outside_block_ignore_multiline && get_line(cx, remove_span) != get_line(cx, insert_span) {
|
||||
return;
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
SEMICOLON_OUTSIDE_BLOCK,
|
||||
block.span,
|
||||
"consider moving the `;` outside the block for consistent formatting",
|
||||
|diag| {
|
||||
multispan_sugg_with_applicability(
|
||||
diag,
|
||||
"put the `;` here",
|
||||
Applicability::MachineApplicable,
|
||||
[(remove_span, String::new()), (insert_span, ";".to_owned())],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl LateLintPass<'_> for SemicolonBlock {
|
||||
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
|
||||
|
@ -83,55 +154,23 @@ impl LateLintPass<'_> for SemicolonBlock {
|
|||
span,
|
||||
..
|
||||
} = stmt else { return };
|
||||
semicolon_outside_block(cx, block, expr, span);
|
||||
self.semicolon_outside_block(cx, block, expr, span);
|
||||
},
|
||||
StmtKind::Semi(Expr {
|
||||
kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _),
|
||||
..
|
||||
}) if !block.span.from_expansion() => semicolon_inside_block(cx, block, tail, stmt.span),
|
||||
}) if !block.span.from_expansion() => {
|
||||
self.semicolon_inside_block(cx, block, tail, stmt.span);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
|
||||
let insert_span = tail.span.source_callsite().shrink_to_hi();
|
||||
let remove_span = semi_span.with_lo(block.span.hi());
|
||||
fn get_line(cx: &LateContext<'_>, span: Span) -> Option<usize> {
|
||||
if let Ok(line) = cx.sess().source_map().lookup_line(span.lo()) {
|
||||
return Some(line.line);
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
SEMICOLON_INSIDE_BLOCK,
|
||||
semi_span,
|
||||
"consider moving the `;` inside the block for consistent formatting",
|
||||
|diag| {
|
||||
multispan_sugg_with_applicability(
|
||||
diag,
|
||||
"put the `;` here",
|
||||
Applicability::MachineApplicable,
|
||||
[(remove_span, String::new()), (insert_span, ";".to_owned())],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) {
|
||||
let insert_span = block.span.with_lo(block.span.hi());
|
||||
// account for macro calls
|
||||
let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
|
||||
let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
SEMICOLON_OUTSIDE_BLOCK,
|
||||
block.span,
|
||||
"consider moving the `;` outside the block for consistent formatting",
|
||||
|diag| {
|
||||
multispan_sugg_with_applicability(
|
||||
diag,
|
||||
"put the `;` here",
|
||||
Applicability::MachineApplicable,
|
||||
[(remove_span, String::new()), (insert_span, ";".to_owned())],
|
||||
);
|
||||
},
|
||||
);
|
||||
None
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for Shadow {
|
|||
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
|
||||
let PatKind::Binding(_, id, ident, _) = pat.kind else { return };
|
||||
|
||||
if pat.span.desugaring_kind().is_some() {
|
||||
if pat.span.desugaring_kind().is_some() || pat.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ enum InitializationType<'tcx> {
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
// Matches initialization on reassignements. For example: `vec = Vec::with_capacity(100)`
|
||||
// Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)`
|
||||
if_chain! {
|
||||
if let ExprKind::Assign(left, right, _) = expr.kind;
|
||||
|
||||
|
|
|
@ -292,6 +292,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
|
|||
}
|
||||
|
||||
if_chain! {
|
||||
if !in_external_macro(cx.sess(), e.span);
|
||||
if let ExprKind::MethodCall(path, receiver, ..) = &e.kind;
|
||||
if path.ident.name == sym!(as_bytes);
|
||||
if let ExprKind::Lit(lit) = &receiver.kind;
|
||||
|
|
|
@ -60,7 +60,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_
|
|||
if let Some(last_field) = data.fields().last();
|
||||
if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind;
|
||||
|
||||
// Then check if that that array zero-sized
|
||||
// Then check if that array is zero-sized
|
||||
let length = Const::from_anon_const(cx.tcx, length.def_id);
|
||||
let length = length.try_eval_target_usize(cx.tcx, cx.param_env);
|
||||
if let Some(length) = length;
|
||||
|
|
|
@ -90,8 +90,8 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// ### Why is this bad?
|
||||
/// `Option<_>` represents an optional value. `Option<Option<_>>`
|
||||
/// represents an optional optional value which is logically the same thing as an optional
|
||||
/// value but has an unneeded extra level of wrapping.
|
||||
/// represents an optional value which itself wraps an optional. This is logically the
|
||||
/// same thing as an optional value but has an unneeded extra level of wrapping.
|
||||
///
|
||||
/// If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases,
|
||||
/// consider a custom `enum` instead, with clear names for each case.
|
||||
|
|
|
@ -76,7 +76,7 @@ declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_
|
|||
|
||||
impl LateLintPass<'_> for Unicode {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
|
||||
if let ExprKind::Lit(ref lit) = expr.kind {
|
||||
if let ExprKind::Lit(lit) = expr.kind {
|
||||
if let LitKind::Str(_, _) | LitKind::Char(_) = lit.node {
|
||||
check_str(cx, lit.span, expr.hir_id);
|
||||
}
|
||||
|
|
|
@ -109,7 +109,7 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns {
|
|||
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
|
||||
// Ignore implementations of traits, because the lint should be on the
|
||||
// trait, not on the implmentation of it.
|
||||
// trait, not on the implementation of it.
|
||||
let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else { return };
|
||||
let ItemKind::Impl(parent) = parent.kind else { return };
|
||||
if parent.of_trait.is_some() {
|
||||
|
|
|
@ -333,7 +333,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn expr(&self, expr: &Binding<&hir::Expr<'_>>) {
|
||||
if let Some(higher::While { condition, body }) = higher::While::hir(expr.value) {
|
||||
if let Some(higher::While { condition, body, .. }) = higher::While::hir(expr.value) {
|
||||
bind!(self, condition, body);
|
||||
chain!(
|
||||
self,
|
||||
|
@ -561,7 +561,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
ExprKind::OffsetOf(container, ref fields) => {
|
||||
bind!(self, container, fields);
|
||||
kind!("OffsetOf({container}, {fields})");
|
||||
}
|
||||
},
|
||||
ExprKind::Struct(qpath, fields, base) => {
|
||||
bind!(self, qpath, fields);
|
||||
opt_bind!(self, base);
|
||||
|
|
|
@ -277,6 +277,14 @@ define_Conf! {
|
|||
/// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
|
||||
/// default configuration of Clippy. By default, any configuration will replace the default value.
|
||||
(disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
|
||||
/// Lint: SEMICOLON_INSIDE_BLOCK.
|
||||
///
|
||||
/// Whether to lint only if it's multiline.
|
||||
(semicolon_inside_block_ignore_singleline: bool = false),
|
||||
/// Lint: SEMICOLON_OUTSIDE_BLOCK.
|
||||
///
|
||||
/// Whether to lint only if it's singleline.
|
||||
(semicolon_outside_block_ignore_multiline: bool = false),
|
||||
/// Lint: DOC_MARKDOWN.
|
||||
///
|
||||
/// The list of words this lint should not consider as identifiers needing ticks. The value
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.70"
|
||||
version = "0.1.71"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
|
|||
ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1),
|
||||
ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1),
|
||||
ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1),
|
||||
ExprKind::Lit(ref lit) => lit_search_pat(&lit.node),
|
||||
ExprKind::Lit(lit) => lit_search_pat(&lit.node),
|
||||
ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")),
|
||||
ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
|
||||
ExprKind::Call(first, [.., last])
|
||||
|
|
|
@ -324,7 +324,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||
match e.kind {
|
||||
ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
|
||||
ExprKind::Block(block, _) => self.block(block),
|
||||
ExprKind::Lit(ref lit) => {
|
||||
ExprKind::Lit(lit) => {
|
||||
if is_direct_expn_of(e.span, "cfg").is_some() {
|
||||
None
|
||||
} else {
|
||||
|
|
|
@ -311,6 +311,8 @@ pub struct While<'hir> {
|
|||
pub condition: &'hir Expr<'hir>,
|
||||
/// `while` loop body
|
||||
pub body: &'hir Expr<'hir>,
|
||||
/// Span of the loop header
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'hir> While<'hir> {
|
||||
|
@ -336,10 +338,10 @@ impl<'hir> While<'hir> {
|
|||
},
|
||||
_,
|
||||
LoopSource::While,
|
||||
_,
|
||||
span,
|
||||
) = expr.kind
|
||||
{
|
||||
return Some(Self { condition, body });
|
||||
return Some(Self { condition, body, span });
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
|
@ -301,7 +301,7 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
(&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
|
||||
(&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
|
||||
(&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re),
|
||||
(&ExprKind::OffsetOf(l_container, ref l_fields), &ExprKind::OffsetOf(r_container, ref r_fields)) => {
|
||||
(&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => {
|
||||
self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name)
|
||||
},
|
||||
_ => false,
|
||||
|
@ -718,7 +718,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
self.hash_pat(pat);
|
||||
},
|
||||
ExprKind::Err(_) => {},
|
||||
ExprKind::Lit(ref l) => {
|
||||
ExprKind::Lit(l) => {
|
||||
l.node.hash(&mut self.s);
|
||||
},
|
||||
ExprKind::Loop(b, ref i, ..) => {
|
||||
|
|
|
@ -86,10 +86,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
|
|||
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
|
||||
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
|
||||
use rustc_hir::{
|
||||
self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination,
|
||||
Expr, ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
|
||||
self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
|
||||
ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
|
||||
MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
|
||||
TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
|
||||
TraitItem, TraitItemRef, TraitRef, TyKind, UnOp,
|
||||
};
|
||||
use rustc_lexer::{tokenize, TokenKind};
|
||||
use rustc_lint::{LateContext, Level, Lint, LintContext};
|
||||
|
@ -197,31 +197,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
|
|||
/// }
|
||||
/// ```
|
||||
pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
|
||||
let parent_id = cx.tcx.hir().get_parent_item(id).def_id;
|
||||
match cx.tcx.hir().get_by_def_id(parent_id) {
|
||||
Node::Item(&Item {
|
||||
kind: ItemKind::Const(..) | ItemKind::Static(..) | ItemKind::Enum(..),
|
||||
..
|
||||
})
|
||||
| Node::TraitItem(&TraitItem {
|
||||
kind: TraitItemKind::Const(..),
|
||||
..
|
||||
})
|
||||
| Node::ImplItem(&ImplItem {
|
||||
kind: ImplItemKind::Const(..),
|
||||
..
|
||||
})
|
||||
| Node::AnonConst(_) => true,
|
||||
Node::Item(&Item {
|
||||
kind: ItemKind::Fn(ref sig, ..),
|
||||
..
|
||||
})
|
||||
| Node::ImplItem(&ImplItem {
|
||||
kind: ImplItemKind::Fn(ref sig, _),
|
||||
..
|
||||
}) => sig.header.constness == Constness::Const,
|
||||
_ => false,
|
||||
}
|
||||
cx.tcx.hir().is_inside_const_context(id)
|
||||
}
|
||||
|
||||
/// Checks if a `Res` refers to a constructor of a `LangItem`
|
||||
|
@ -846,7 +822,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
|||
},
|
||||
ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
|
||||
ExprKind::Repeat(x, ArrayLen::Body(len)) => if_chain! {
|
||||
if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind;
|
||||
if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind;
|
||||
if let LitKind::Int(v, _) = const_lit.node;
|
||||
if v <= 32 && is_default_equivalent(cx, x);
|
||||
then {
|
||||
|
@ -875,7 +851,7 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
|
|||
}) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String),
|
||||
ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
|
||||
ExprKind::Repeat(_, ArrayLen::Body(len)) => {
|
||||
if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind &&
|
||||
if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind &&
|
||||
let LitKind::Int(v, _) = const_lit.node
|
||||
{
|
||||
return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);
|
||||
|
@ -1569,7 +1545,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool
|
|||
/// Checks whether the given expression is a constant literal of the given value.
|
||||
pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
|
||||
// FIXME: use constant folding
|
||||
if let ExprKind::Lit(ref spanned) = expr.kind {
|
||||
if let ExprKind::Lit(spanned) = expr.kind {
|
||||
if let LitKind::Int(v, _) = spanned.node {
|
||||
return v == value;
|
||||
}
|
||||
|
@ -2165,10 +2141,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
|
|||
.predicates
|
||||
.iter()
|
||||
.filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
|
||||
traits::impossible_predicates(
|
||||
cx.tcx,
|
||||
traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>(),
|
||||
)
|
||||
traits::impossible_predicates(cx.tcx, traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
/// Returns the `DefId` of the callee if the given expression is a function or method call.
|
||||
|
@ -2233,8 +2206,12 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S
|
|||
None
|
||||
}
|
||||
|
||||
/// returns list of all pairs (a, b) from `exprs` such that `eq(a, b)`
|
||||
/// `hash` must be comformed with `eq`
|
||||
/// Returns list of all pairs `(a, b)` where `eq(a, b) == true`
|
||||
/// and `a` is before `b` in `exprs` for all `a` and `b` in
|
||||
/// `exprs`
|
||||
///
|
||||
/// Given functions `eq` and `hash` such that `eq(a, b) == true`
|
||||
/// implies `hash(a) == hash(b)`
|
||||
pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
|
||||
where
|
||||
Hash: Fn(&T) -> u64,
|
||||
|
|
|
@ -362,7 +362,7 @@ thread_local! {
|
|||
/// able to access the many features of a [`LateContext`].
|
||||
///
|
||||
/// A thread local is used because [`FormatArgs`] is `!Send` and `!Sync`, we are making an
|
||||
/// assumption that the early pass the populates the map and the later late passes will all be
|
||||
/// assumption that the early pass that populates the map and the later late passes will all be
|
||||
/// running on the same thread.
|
||||
static AST_FORMAT_ARGS: RefCell<FxHashMap<Span, FormatArgs>> = {
|
||||
static CALLED: AtomicBool = AtomicBool::new(false);
|
||||
|
|
|
@ -159,3 +159,7 @@ pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
|
|||
pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
|
||||
pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
|
||||
pub const INSTANT: [&str; 3] = ["std", "time", "Instant"];
|
||||
pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"];
|
||||
pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"];
|
||||
pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
|
||||
pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
|
||||
|
|
|
@ -194,7 +194,9 @@ fn check_rvalue<'tcx>(
|
|||
))
|
||||
}
|
||||
},
|
||||
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) | Rvalue::ShallowInitBox(_, _) => Ok(()),
|
||||
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) | Rvalue::ShallowInitBox(_, _) => {
|
||||
Ok(())
|
||||
},
|
||||
Rvalue::UnaryOp(_, operand) => {
|
||||
let ty = operand.ty(body, tcx);
|
||||
if ty.is_integral() || ty.is_bool() {
|
||||
|
|
|
@ -162,7 +162,7 @@ impl<'a> Sugg<'a> {
|
|||
get_snippet(lhs.span),
|
||||
get_snippet(rhs.span),
|
||||
),
|
||||
hir::ExprKind::Cast(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)),
|
||||
hir::ExprKind::Cast(lhs, ty) |
|
||||
//FIXME(chenyukang), remove this after type ascription is removed from AST
|
||||
hir::ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)),
|
||||
}
|
||||
|
@ -254,11 +254,7 @@ impl<'a> Sugg<'a> {
|
|||
snippet_with_context(cx, lhs.span, ctxt, default, app).0,
|
||||
snippet_with_context(cx, rhs.span, ctxt, default, app).0,
|
||||
),
|
||||
ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp(
|
||||
AssocOp::As,
|
||||
snippet_with_context(cx, lhs.span, ctxt, default, app).0,
|
||||
snippet_with_context(cx, ty.span, ctxt, default, app).0,
|
||||
),
|
||||
ast::ExprKind::Cast(ref lhs, ref ty) |
|
||||
//FIXME(chenyukang), remove this after type ascription is removed from AST
|
||||
ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp(
|
||||
AssocOp::As,
|
||||
|
@ -603,8 +599,8 @@ enum Associativity {
|
|||
#[must_use]
|
||||
fn associativity(op: AssocOp) -> Associativity {
|
||||
use rustc_ast::util::parser::AssocOp::{
|
||||
Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Divide, DotDot, DotDotEq, Equal, Greater,
|
||||
GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
|
||||
Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Divide, DotDot, DotDotEq, Equal, Greater, GreaterEqual, LAnd,
|
||||
LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
|
||||
};
|
||||
|
||||
match op {
|
||||
|
|
|
@ -93,7 +93,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
|
|||
for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() {
|
||||
match predicate.kind().skip_binder() {
|
||||
// For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
|
||||
// and check substituions to find `U`.
|
||||
// and check substitutions to find `U`.
|
||||
ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
|
||||
if trait_predicate
|
||||
.trait_ref
|
||||
|
@ -837,7 +837,7 @@ pub fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
|
|||
if let ty::Adt(adt, _) = ty.kind()
|
||||
&& let &[krate, .., name] = &*cx.get_def_path(adt.did())
|
||||
&& let sym::libc | sym::core | sym::std = krate
|
||||
&& name.as_str() == "c_void"
|
||||
&& name == rustc_span::sym::c_void
|
||||
{
|
||||
true
|
||||
} else {
|
||||
|
@ -1101,7 +1101,7 @@ pub fn make_projection<'tcx>(
|
|||
///
|
||||
/// This function is for associated types which are "known" to be valid with the given
|
||||
/// substitutions, and as such, will only return `None` when debug assertions are disabled in order
|
||||
/// to prevent ICE's. With debug assertions enabled this will check that that type normalization
|
||||
/// to prevent ICE's. With debug assertions enabled this will check that type normalization
|
||||
/// succeeds as well as everything checked by `make_projection`.
|
||||
pub fn make_normalized_projection<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.70"
|
||||
version = "0.1.71"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
|
|
|
@ -79,9 +79,11 @@ is explicitly specified in the options.
|
|||
|
||||
### Fix mode
|
||||
You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and
|
||||
print a warning if Clippy's suggestions fail to apply (if the resulting code does not build).
|
||||
print a warning if Clippy's suggestions fail to apply (if the resulting code does not build).
|
||||
This lets us spot bad suggestions or false positives automatically in some cases.
|
||||
|
||||
> Note: Fix mode implies `--all-targets`, so it can fix as much code as it can.
|
||||
|
||||
Please note that the target dir should be cleaned afterwards since clippy will modify
|
||||
the downloaded sources which can lead to unexpected results when running lintcheck again afterwards.
|
||||
|
||||
|
|
|
@ -421,7 +421,7 @@ impl Crate {
|
|||
{
|
||||
let subcrate = &stderr[63..];
|
||||
println!(
|
||||
"ERROR: failed to apply some suggetion to {} / to (sub)crate {subcrate}",
|
||||
"ERROR: failed to apply some suggestion to {} / to (sub)crate {subcrate}",
|
||||
self.name
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ Usage:
|
|||
|
||||
Common options:
|
||||
--no-deps Run Clippy only on the given crate, without linting the dependencies
|
||||
--fix Automatically apply lint suggestions. This flag implies `--no-deps`
|
||||
--fix Automatically apply lint suggestions. This flag implies `--no-deps` and `--all-targets`
|
||||
-h, --help Print this message
|
||||
-V, --version Print version info and exit
|
||||
--explain LINT Print the documentation for a given lint
|
||||
|
|
|
@ -39,7 +39,7 @@ fn dogfood_clippy() {
|
|||
assert!(
|
||||
failed_packages.is_empty(),
|
||||
"Dogfood failed for packages `{}`",
|
||||
failed_packages.iter().format(", "),
|
||||
failed_packages.iter().join(", "),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
86
tests/ui-toml/semicolon_block/both.fixed
Normal file
86
tests/ui-toml/semicolon_block/both.fixed
Normal file
|
@ -0,0 +1,86 @@
|
|||
//@run-rustfix
|
||||
#![allow(
|
||||
unused,
|
||||
clippy::unused_unit,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::no_effect,
|
||||
clippy::single_element_loop
|
||||
)]
|
||||
#![warn(clippy::semicolon_inside_block)]
|
||||
#![warn(clippy::semicolon_outside_block)]
|
||||
|
||||
macro_rules! m {
|
||||
(()) => {
|
||||
()
|
||||
};
|
||||
(0) => {{
|
||||
0
|
||||
};};
|
||||
(1) => {{
|
||||
1;
|
||||
}};
|
||||
(2) => {{
|
||||
2;
|
||||
}};
|
||||
}
|
||||
|
||||
fn unit_fn_block() {
|
||||
()
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn main() {
|
||||
{ unit_fn_block() }
|
||||
unsafe { unit_fn_block() }
|
||||
|
||||
{
|
||||
unit_fn_block()
|
||||
}
|
||||
|
||||
{ unit_fn_block() };
|
||||
unsafe { unit_fn_block() };
|
||||
|
||||
{ unit_fn_block() };
|
||||
unsafe { unit_fn_block() };
|
||||
|
||||
{ unit_fn_block(); };
|
||||
unsafe { unit_fn_block(); };
|
||||
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
}
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
}
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
};
|
||||
|
||||
{ m!(()) };
|
||||
{ m!(()) };
|
||||
{ m!(()); };
|
||||
m!(0);
|
||||
m!(1);
|
||||
m!(2);
|
||||
|
||||
for _ in [()] {
|
||||
unit_fn_block();
|
||||
}
|
||||
for _ in [()] {
|
||||
unit_fn_block()
|
||||
}
|
||||
|
||||
let _d = || {
|
||||
unit_fn_block();
|
||||
};
|
||||
let _d = || {
|
||||
unit_fn_block()
|
||||
};
|
||||
|
||||
{ unit_fn_block(); };
|
||||
|
||||
unit_fn_block()
|
||||
}
|
86
tests/ui-toml/semicolon_block/both.rs
Normal file
86
tests/ui-toml/semicolon_block/both.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
//@run-rustfix
|
||||
#![allow(
|
||||
unused,
|
||||
clippy::unused_unit,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::no_effect,
|
||||
clippy::single_element_loop
|
||||
)]
|
||||
#![warn(clippy::semicolon_inside_block)]
|
||||
#![warn(clippy::semicolon_outside_block)]
|
||||
|
||||
macro_rules! m {
|
||||
(()) => {
|
||||
()
|
||||
};
|
||||
(0) => {{
|
||||
0
|
||||
};};
|
||||
(1) => {{
|
||||
1;
|
||||
}};
|
||||
(2) => {{
|
||||
2;
|
||||
}};
|
||||
}
|
||||
|
||||
fn unit_fn_block() {
|
||||
()
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn main() {
|
||||
{ unit_fn_block() }
|
||||
unsafe { unit_fn_block() }
|
||||
|
||||
{
|
||||
unit_fn_block()
|
||||
}
|
||||
|
||||
{ unit_fn_block() };
|
||||
unsafe { unit_fn_block() };
|
||||
|
||||
{ unit_fn_block(); }
|
||||
unsafe { unit_fn_block(); }
|
||||
|
||||
{ unit_fn_block(); };
|
||||
unsafe { unit_fn_block(); };
|
||||
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block()
|
||||
};
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
}
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
};
|
||||
|
||||
{ m!(()) };
|
||||
{ m!(()); }
|
||||
{ m!(()); };
|
||||
m!(0);
|
||||
m!(1);
|
||||
m!(2);
|
||||
|
||||
for _ in [()] {
|
||||
unit_fn_block();
|
||||
}
|
||||
for _ in [()] {
|
||||
unit_fn_block()
|
||||
}
|
||||
|
||||
let _d = || {
|
||||
unit_fn_block();
|
||||
};
|
||||
let _d = || {
|
||||
unit_fn_block()
|
||||
};
|
||||
|
||||
{ unit_fn_block(); };
|
||||
|
||||
unit_fn_block()
|
||||
}
|
55
tests/ui-toml/semicolon_block/both.stderr
Normal file
55
tests/ui-toml/semicolon_block/both.stderr
Normal file
|
@ -0,0 +1,55 @@
|
|||
error: consider moving the `;` outside the block for consistent formatting
|
||||
--> $DIR/both.rs:43:5
|
||||
|
|
||||
LL | { unit_fn_block(); }
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::semicolon-outside-block` implied by `-D warnings`
|
||||
help: put the `;` here
|
||||
|
|
||||
LL - { unit_fn_block(); }
|
||||
LL + { unit_fn_block() };
|
||||
|
|
||||
|
||||
error: consider moving the `;` outside the block for consistent formatting
|
||||
--> $DIR/both.rs:44:5
|
||||
|
|
||||
LL | unsafe { unit_fn_block(); }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: put the `;` here
|
||||
|
|
||||
LL - unsafe { unit_fn_block(); }
|
||||
LL + unsafe { unit_fn_block() };
|
||||
|
|
||||
|
||||
error: consider moving the `;` inside the block for consistent formatting
|
||||
--> $DIR/both.rs:49:5
|
||||
|
|
||||
LL | / {
|
||||
LL | | unit_fn_block();
|
||||
LL | | unit_fn_block()
|
||||
LL | | };
|
||||
| |______^
|
||||
|
|
||||
= note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
|
||||
help: put the `;` here
|
||||
|
|
||||
LL ~ unit_fn_block();
|
||||
LL ~ }
|
||||
|
|
||||
|
||||
error: consider moving the `;` outside the block for consistent formatting
|
||||
--> $DIR/both.rs:63:5
|
||||
|
|
||||
LL | { m!(()); }
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
help: put the `;` here
|
||||
|
|
||||
LL - { m!(()); }
|
||||
LL + { m!(()) };
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
2
tests/ui-toml/semicolon_block/clippy.toml
Normal file
2
tests/ui-toml/semicolon_block/clippy.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
semicolon-inside-block-ignore-singleline = true
|
||||
semicolon-outside-block-ignore-multiline = true
|
85
tests/ui-toml/semicolon_block/semicolon_inside_block.fixed
Normal file
85
tests/ui-toml/semicolon_block/semicolon_inside_block.fixed
Normal file
|
@ -0,0 +1,85 @@
|
|||
//@run-rustfix
|
||||
#![allow(
|
||||
unused,
|
||||
clippy::unused_unit,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::no_effect,
|
||||
clippy::single_element_loop
|
||||
)]
|
||||
#![warn(clippy::semicolon_inside_block)]
|
||||
|
||||
macro_rules! m {
|
||||
(()) => {
|
||||
()
|
||||
};
|
||||
(0) => {{
|
||||
0
|
||||
};};
|
||||
(1) => {{
|
||||
1;
|
||||
}};
|
||||
(2) => {{
|
||||
2;
|
||||
}};
|
||||
}
|
||||
|
||||
fn unit_fn_block() {
|
||||
()
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn main() {
|
||||
{ unit_fn_block() }
|
||||
unsafe { unit_fn_block() }
|
||||
|
||||
{
|
||||
unit_fn_block()
|
||||
}
|
||||
|
||||
{ unit_fn_block() };
|
||||
unsafe { unit_fn_block() };
|
||||
|
||||
{ unit_fn_block(); }
|
||||
unsafe { unit_fn_block(); }
|
||||
|
||||
{ unit_fn_block(); };
|
||||
unsafe { unit_fn_block(); };
|
||||
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
}
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
}
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
};
|
||||
|
||||
{ m!(()) };
|
||||
{ m!(()); }
|
||||
{ m!(()); };
|
||||
m!(0);
|
||||
m!(1);
|
||||
m!(2);
|
||||
|
||||
for _ in [()] {
|
||||
unit_fn_block();
|
||||
}
|
||||
for _ in [()] {
|
||||
unit_fn_block()
|
||||
}
|
||||
|
||||
let _d = || {
|
||||
unit_fn_block();
|
||||
};
|
||||
let _d = || {
|
||||
unit_fn_block()
|
||||
};
|
||||
|
||||
{ unit_fn_block(); };
|
||||
|
||||
unit_fn_block()
|
||||
}
|
85
tests/ui-toml/semicolon_block/semicolon_inside_block.rs
Normal file
85
tests/ui-toml/semicolon_block/semicolon_inside_block.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
//@run-rustfix
|
||||
#![allow(
|
||||
unused,
|
||||
clippy::unused_unit,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::no_effect,
|
||||
clippy::single_element_loop
|
||||
)]
|
||||
#![warn(clippy::semicolon_inside_block)]
|
||||
|
||||
macro_rules! m {
|
||||
(()) => {
|
||||
()
|
||||
};
|
||||
(0) => {{
|
||||
0
|
||||
};};
|
||||
(1) => {{
|
||||
1;
|
||||
}};
|
||||
(2) => {{
|
||||
2;
|
||||
}};
|
||||
}
|
||||
|
||||
fn unit_fn_block() {
|
||||
()
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn main() {
|
||||
{ unit_fn_block() }
|
||||
unsafe { unit_fn_block() }
|
||||
|
||||
{
|
||||
unit_fn_block()
|
||||
}
|
||||
|
||||
{ unit_fn_block() };
|
||||
unsafe { unit_fn_block() };
|
||||
|
||||
{ unit_fn_block(); }
|
||||
unsafe { unit_fn_block(); }
|
||||
|
||||
{ unit_fn_block(); };
|
||||
unsafe { unit_fn_block(); };
|
||||
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block()
|
||||
};
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
}
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
};
|
||||
|
||||
{ m!(()) };
|
||||
{ m!(()); }
|
||||
{ m!(()); };
|
||||
m!(0);
|
||||
m!(1);
|
||||
m!(2);
|
||||
|
||||
for _ in [()] {
|
||||
unit_fn_block();
|
||||
}
|
||||
for _ in [()] {
|
||||
unit_fn_block()
|
||||
}
|
||||
|
||||
let _d = || {
|
||||
unit_fn_block();
|
||||
};
|
||||
let _d = || {
|
||||
unit_fn_block()
|
||||
};
|
||||
|
||||
{ unit_fn_block(); };
|
||||
|
||||
unit_fn_block()
|
||||
}
|
18
tests/ui-toml/semicolon_block/semicolon_inside_block.stderr
Normal file
18
tests/ui-toml/semicolon_block/semicolon_inside_block.stderr
Normal file
|
@ -0,0 +1,18 @@
|
|||
error: consider moving the `;` inside the block for consistent formatting
|
||||
--> $DIR/semicolon_inside_block.rs:48:5
|
||||
|
|
||||
LL | / {
|
||||
LL | | unit_fn_block();
|
||||
LL | | unit_fn_block()
|
||||
LL | | };
|
||||
| |______^
|
||||
|
|
||||
= note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
|
||||
help: put the `;` here
|
||||
|
|
||||
LL ~ unit_fn_block();
|
||||
LL ~ }
|
||||
|
|
||||
|
||||
error: aborting due to previous error
|
||||
|
85
tests/ui-toml/semicolon_block/semicolon_outside_block.fixed
Normal file
85
tests/ui-toml/semicolon_block/semicolon_outside_block.fixed
Normal file
|
@ -0,0 +1,85 @@
|
|||
//@run-rustfix
|
||||
#![allow(
|
||||
unused,
|
||||
clippy::unused_unit,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::no_effect,
|
||||
clippy::single_element_loop
|
||||
)]
|
||||
#![warn(clippy::semicolon_outside_block)]
|
||||
|
||||
macro_rules! m {
|
||||
(()) => {
|
||||
()
|
||||
};
|
||||
(0) => {{
|
||||
0
|
||||
};};
|
||||
(1) => {{
|
||||
1;
|
||||
}};
|
||||
(2) => {{
|
||||
2;
|
||||
}};
|
||||
}
|
||||
|
||||
fn unit_fn_block() {
|
||||
()
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn main() {
|
||||
{ unit_fn_block() }
|
||||
unsafe { unit_fn_block() }
|
||||
|
||||
{
|
||||
unit_fn_block()
|
||||
}
|
||||
|
||||
{ unit_fn_block() };
|
||||
unsafe { unit_fn_block() };
|
||||
|
||||
{ unit_fn_block() };
|
||||
unsafe { unit_fn_block() };
|
||||
|
||||
{ unit_fn_block(); };
|
||||
unsafe { unit_fn_block(); };
|
||||
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block()
|
||||
};
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
}
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
};
|
||||
|
||||
{ m!(()) };
|
||||
{ m!(()) };
|
||||
{ m!(()); };
|
||||
m!(0);
|
||||
m!(1);
|
||||
m!(2);
|
||||
|
||||
for _ in [()] {
|
||||
unit_fn_block();
|
||||
}
|
||||
for _ in [()] {
|
||||
unit_fn_block()
|
||||
}
|
||||
|
||||
let _d = || {
|
||||
unit_fn_block();
|
||||
};
|
||||
let _d = || {
|
||||
unit_fn_block()
|
||||
};
|
||||
|
||||
{ unit_fn_block(); };
|
||||
|
||||
unit_fn_block()
|
||||
}
|
85
tests/ui-toml/semicolon_block/semicolon_outside_block.rs
Normal file
85
tests/ui-toml/semicolon_block/semicolon_outside_block.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
//@run-rustfix
|
||||
#![allow(
|
||||
unused,
|
||||
clippy::unused_unit,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::no_effect,
|
||||
clippy::single_element_loop
|
||||
)]
|
||||
#![warn(clippy::semicolon_outside_block)]
|
||||
|
||||
macro_rules! m {
|
||||
(()) => {
|
||||
()
|
||||
};
|
||||
(0) => {{
|
||||
0
|
||||
};};
|
||||
(1) => {{
|
||||
1;
|
||||
}};
|
||||
(2) => {{
|
||||
2;
|
||||
}};
|
||||
}
|
||||
|
||||
fn unit_fn_block() {
|
||||
()
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn main() {
|
||||
{ unit_fn_block() }
|
||||
unsafe { unit_fn_block() }
|
||||
|
||||
{
|
||||
unit_fn_block()
|
||||
}
|
||||
|
||||
{ unit_fn_block() };
|
||||
unsafe { unit_fn_block() };
|
||||
|
||||
{ unit_fn_block(); }
|
||||
unsafe { unit_fn_block(); }
|
||||
|
||||
{ unit_fn_block(); };
|
||||
unsafe { unit_fn_block(); };
|
||||
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block()
|
||||
};
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
}
|
||||
{
|
||||
unit_fn_block();
|
||||
unit_fn_block();
|
||||
};
|
||||
|
||||
{ m!(()) };
|
||||
{ m!(()); }
|
||||
{ m!(()); };
|
||||
m!(0);
|
||||
m!(1);
|
||||
m!(2);
|
||||
|
||||
for _ in [()] {
|
||||
unit_fn_block();
|
||||
}
|
||||
for _ in [()] {
|
||||
unit_fn_block()
|
||||
}
|
||||
|
||||
let _d = || {
|
||||
unit_fn_block();
|
||||
};
|
||||
let _d = || {
|
||||
unit_fn_block()
|
||||
};
|
||||
|
||||
{ unit_fn_block(); };
|
||||
|
||||
unit_fn_block()
|
||||
}
|
39
tests/ui-toml/semicolon_block/semicolon_outside_block.stderr
Normal file
39
tests/ui-toml/semicolon_block/semicolon_outside_block.stderr
Normal file
|
@ -0,0 +1,39 @@
|
|||
error: consider moving the `;` outside the block for consistent formatting
|
||||
--> $DIR/semicolon_outside_block.rs:42:5
|
||||
|
|
||||
LL | { unit_fn_block(); }
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::semicolon-outside-block` implied by `-D warnings`
|
||||
help: put the `;` here
|
||||
|
|
||||
LL - { unit_fn_block(); }
|
||||
LL + { unit_fn_block() };
|
||||
|
|
||||
|
||||
error: consider moving the `;` outside the block for consistent formatting
|
||||
--> $DIR/semicolon_outside_block.rs:43:5
|
||||
|
|
||||
LL | unsafe { unit_fn_block(); }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: put the `;` here
|
||||
|
|
||||
LL - unsafe { unit_fn_block(); }
|
||||
LL + unsafe { unit_fn_block() };
|
||||
|
|
||||
|
||||
error: consider moving the `;` outside the block for consistent formatting
|
||||
--> $DIR/semicolon_outside_block.rs:62:5
|
||||
|
|
||||
LL | { m!(()); }
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
help: put the `;` here
|
||||
|
|
||||
LL - { m!(()); }
|
||||
LL + { m!(()) };
|
||||
|
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
|
@ -37,6 +37,8 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
|
|||
missing-docs-in-crate-items
|
||||
msrv
|
||||
pass-by-value-size-limit
|
||||
semicolon-inside-block-ignore-singleline
|
||||
semicolon-outside-block-ignore-multiline
|
||||
single-char-binding-names-threshold
|
||||
standard-macro-braces
|
||||
suppress-restriction-lint-in-const
|
||||
|
|
5
tests/ui/allow_attributes_false_positive.rs
Normal file
5
tests/ui/allow_attributes_false_positive.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
#![warn(clippy::allow_attributes)]
|
||||
#![feature(lint_reasons)]
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
fn main() {}
|
|
@ -21,6 +21,13 @@ macro_rules! string_add {
|
|||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! string_lit_as_bytes {
|
||||
($s:literal) => {
|
||||
const C: &[u8] = $s.as_bytes();
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! mut_mut {
|
||||
() => {
|
||||
|
|
|
@ -82,7 +82,7 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea
|
|||
elided += 1;
|
||||
|
||||
// HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it.
|
||||
// In order to avoid adding the dependency, get a default span from a non-existent token.
|
||||
// In order to avoid adding the dependency, get a default span from a nonexistent token.
|
||||
// A default span is needed to mark the code as coming from expansion.
|
||||
let span = Star::default().span();
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue