mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-10 07:04:18 +00:00
Merge commit '2f6439ae6a6803d030cceb3ee14c9150e91b328b' into clippyup
This commit is contained in:
parent
adb7fc6283
commit
fbf2430f02
109 changed files with 1502 additions and 616 deletions
129
CHANGELOG.md
129
CHANGELOG.md
|
@ -6,11 +6,129 @@ document.
|
|||
|
||||
## Unreleased / In Rust Nightly
|
||||
|
||||
[09bd400...master](https://github.com/rust-lang/rust-clippy/compare/09bd400...master)
|
||||
[e636b88...master](https://github.com/rust-lang/rust-clippy/compare/e636b88...master)
|
||||
|
||||
## Rust 1.48
|
||||
|
||||
Current beta, release 2020-11-19
|
||||
|
||||
[09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88)
|
||||
|
||||
### New lints
|
||||
|
||||
* [`self_assignment`] [#5894](https://github.com/rust-lang/rust-clippy/pull/5894)
|
||||
* [`unnecessary_lazy_evaluations`] [#5720](https://github.com/rust-lang/rust-clippy/pull/5720)
|
||||
* [`manual_strip`] [#6038](https://github.com/rust-lang/rust-clippy/pull/6038)
|
||||
* [`map_err_ignore`] [#5998](https://github.com/rust-lang/rust-clippy/pull/5998)
|
||||
* [`rc_buffer`] [#6044](https://github.com/rust-lang/rust-clippy/pull/6044)
|
||||
* [`to_string_in_display`] [#5831](https://github.com/rust-lang/rust-clippy/pull/5831)
|
||||
* [`single_char_push_str`] [#5881](https://github.com/rust-lang/rust-clippy/pull/5881)
|
||||
|
||||
### Moves and Deprecations
|
||||
|
||||
* Downgrade [`verbose_bit_mask`] to pedantic
|
||||
[#6036](https://github.com/rust-lang/rust-clippy/pull/6036)
|
||||
|
||||
### Enhancements
|
||||
|
||||
* Extend [`precedence`] to handle chains of methods combined with unary negation
|
||||
[#5928](https://github.com/rust-lang/rust-clippy/pull/5928)
|
||||
* [`useless_vec`]: add a configuration value for the maximum allowed size on the stack
|
||||
[#5907](https://github.com/rust-lang/rust-clippy/pull/5907)
|
||||
* [`suspicious_arithmetic_impl`]: extend to implementations of `BitAnd`, `BitOr`, `BitXor`, `Rem`, `Shl`, and `Shr`
|
||||
[#5884](https://github.com/rust-lang/rust-clippy/pull/5884)
|
||||
* [`invalid_atomic_ordering`]: detect misuse of `compare_exchange`, `compare_exchange_weak`, and `fetch_update`
|
||||
[#6025](https://github.com/rust-lang/rust-clippy/pull/6025)
|
||||
* Avoid [`redundant_pattern_matching`] triggering in macros
|
||||
[#6069](https://github.com/rust-lang/rust-clippy/pull/6069)
|
||||
* [`option_if_let_else`]: distinguish pure from impure `else` expressions
|
||||
[#5937](https://github.com/rust-lang/rust-clippy/pull/5937)
|
||||
* [`needless_doctest_main`]: parse doctests instead of using textual search
|
||||
[#5912](https://github.com/rust-lang/rust-clippy/pull/5912)
|
||||
* [`wildcard_imports`]: allow `prelude` to appear in any segment of an import
|
||||
[#5929](https://github.com/rust-lang/rust-clippy/pull/5929)
|
||||
* Re-enable [`len_zero`] for ranges now that `range_is_empty` is stable
|
||||
[#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
|
||||
* [`option_as_ref_deref`]: catch fully-qualified calls to `Deref::deref` and `DerefMut::deref_mut`
|
||||
[#5933](https://github.com/rust-lang/rust-clippy/pull/5933)
|
||||
|
||||
### False Positive Fixes
|
||||
|
||||
* [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`]
|
||||
[#5994](https://github.com/rust-lang/rust-clippy/pull/5994)
|
||||
* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts
|
||||
[#5999](https://github.com/rust-lang/rust-clippy/pull/5999)
|
||||
* [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures
|
||||
[#5920](https://github.com/rust-lang/rust-clippy/pull/5920)
|
||||
* Fix false positive in [`borrow_interior_mutable_const`] when referencing a field behind a pointer
|
||||
[#5949](https://github.com/rust-lang/rust-clippy/pull/5949)
|
||||
* [`doc_markdown`]: allow using "GraphQL" without backticks
|
||||
[#5996](https://github.com/rust-lang/rust-clippy/pull/5996)
|
||||
* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self`
|
||||
[#5971](https://github.com/rust-lang/rust-clippy/pull/5971)
|
||||
* [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays
|
||||
[#6034](https://github.com/rust-lang/rust-clippy/pull/6034)
|
||||
* [`should_implement_trait`]: ignore methods with lifetime parameters
|
||||
[#5725](https://github.com/rust-lang/rust-clippy/pull/5725)
|
||||
* [`needless_return`]: avoid linting if a temporary borrows a local variable
|
||||
[#5903](https://github.com/rust-lang/rust-clippy/pull/5903)
|
||||
* Restrict [`unnecessary_sort_by`] to non-reference, Copy types
|
||||
[#6006](https://github.com/rust-lang/rust-clippy/pull/6006)
|
||||
* Avoid suggesting `from_bits`/`to_bits` in const contexts in [`transmute_int_to_float`]
|
||||
[#5919](https://github.com/rust-lang/rust-clippy/pull/5919)
|
||||
* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]: improve detection of interior mutable types
|
||||
[#6046](https://github.com/rust-lang/rust-clippy/pull/6046)
|
||||
|
||||
### Suggestion Fixes/Improvements
|
||||
|
||||
* [`let_and_return`]: add a cast to the suggestion when the return expression has adjustments
|
||||
[#5946](https://github.com/rust-lang/rust-clippy/pull/5946)
|
||||
* [`useless_conversion`]: show the type in the error message
|
||||
[#6035](https://github.com/rust-lang/rust-clippy/pull/6035)
|
||||
* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message
|
||||
[#5892](https://github.com/rust-lang/rust-clippy/pull/5892)
|
||||
* [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous
|
||||
[#6043](https://github.com/rust-lang/rust-clippy/pull/6043)
|
||||
* [`default_trait_access`]: do not use unnecessary type parameters in the suggestion
|
||||
[#5993](https://github.com/rust-lang/rust-clippy/pull/5993)
|
||||
* [`collapsible_if`]: don't use expanded code in the suggestion
|
||||
[#5992](https://github.com/rust-lang/rust-clippy/pull/5992)
|
||||
* Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`]
|
||||
[#6042](https://github.com/rust-lang/rust-clippy/pull/6042)
|
||||
* [`unit_arg`]: improve the readability of the suggestion
|
||||
[#5931](https://github.com/rust-lang/rust-clippy/pull/5931)
|
||||
* [`stable_sort_primitive`]: print the type that is being sorted in the lint message
|
||||
[#5935](https://github.com/rust-lang/rust-clippy/pull/5935)
|
||||
* Show line count and max lines in [`too_many_lines`] lint message
|
||||
[#6009](https://github.com/rust-lang/rust-clippy/pull/6009)
|
||||
* Keep parentheses in the suggestion of [`useless_conversion`] where applicable
|
||||
[#5900](https://github.com/rust-lang/rust-clippy/pull/5900)
|
||||
* [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly
|
||||
[#6024](https://github.com/rust-lang/rust-clippy/pull/6024)
|
||||
* [`redundant_allocation`]: suggest replacing `Rc<Box<T>>` with `Rc<T>`
|
||||
[#5899](https://github.com/rust-lang/rust-clippy/pull/5899)
|
||||
* Make lint messages adhere to rustc dev guide conventions
|
||||
[#5893](https://github.com/rust-lang/rust-clippy/pull/5893)
|
||||
|
||||
### ICE Fixes
|
||||
|
||||
* Fix ICE in [`repeat_once`]
|
||||
[#5948](https://github.com/rust-lang/rust-clippy/pull/5948)
|
||||
|
||||
### Documentation Improvements
|
||||
|
||||
* [`mutable_key_type`]: explain potential for false positives when the interior mutable type is not accessed in the `Hash` implementation
|
||||
[#6019](https://github.com/rust-lang/rust-clippy/pull/6019)
|
||||
* [`unnecessary_mut_passed`]: fix typo
|
||||
[#5913](https://github.com/rust-lang/rust-clippy/pull/5913)
|
||||
* Add example of false positive to [`ptr_arg`] docs.
|
||||
[#5885](https://github.com/rust-lang/rust-clippy/pull/5885)
|
||||
* [`box_vec`], [`vec_box`] and [`borrowed_box`]: add link to the documentation of `Box`
|
||||
[#6023](https://github.com/rust-lang/rust-clippy/pull/6023)
|
||||
|
||||
## Rust 1.47
|
||||
|
||||
Current beta, release 2020-10-08
|
||||
Current stable, released 2020-10-08
|
||||
|
||||
[c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400)
|
||||
|
||||
|
@ -112,7 +230,7 @@ Current beta, release 2020-10-08
|
|||
|
||||
## Rust 1.46
|
||||
|
||||
Current stable, released 2020-08-27
|
||||
Released 2020-08-27
|
||||
|
||||
[7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa)
|
||||
|
||||
|
@ -1559,6 +1677,7 @@ Released 2018-09-13
|
|||
[`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
|
||||
[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
|
||||
[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
|
||||
[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
|
||||
[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
|
||||
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
|
||||
[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
|
||||
|
@ -1634,6 +1753,8 @@ Released 2018-09-13
|
|||
[`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string
|
||||
[`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display
|
||||
[`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always
|
||||
[`inline_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax
|
||||
[`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax
|
||||
[`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body
|
||||
[`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
|
||||
[`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
|
||||
|
@ -1644,6 +1765,7 @@ Released 2018-09-13
|
|||
[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
|
||||
[`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
|
||||
[`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
|
||||
[`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters
|
||||
[`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements
|
||||
[`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect
|
||||
[`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
|
||||
|
@ -1919,6 +2041,5 @@ Released 2018-09-13
|
|||
[`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero
|
||||
[`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
|
||||
[`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr
|
||||
[`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space
|
||||
[`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
|
||||
<!-- end autogenerated links to lint list -->
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
|
||||
|
||||
[There are over 350 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
|
||||
[There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
|
||||
|
||||
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ edition = "2018"
|
|||
bytecount = "0.6"
|
||||
clap = "2.33"
|
||||
itertools = "0.9"
|
||||
opener = "0.4"
|
||||
regex = "1"
|
||||
lazy_static = "1.0"
|
||||
shell-escape = "0.1"
|
||||
walkdir = "2"
|
||||
|
||||
|
|
|
@ -1,42 +1,47 @@
|
|||
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
|
||||
#![feature(once_cell)]
|
||||
|
||||
use itertools::Itertools;
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::lazy::SyncLazy;
|
||||
use std::path::{Path, PathBuf};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
pub mod fmt;
|
||||
pub mod new_lint;
|
||||
pub mod ra_setup;
|
||||
pub mod serve;
|
||||
pub mod stderr_length_check;
|
||||
pub mod update_lints;
|
||||
|
||||
lazy_static! {
|
||||
static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(
|
||||
static DEC_CLIPPY_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
|
||||
Regex::new(
|
||||
r#"(?x)
|
||||
declare_clippy_lint!\s*[\{(]
|
||||
(?:\s+///.*)*
|
||||
\s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
|
||||
(?P<cat>[a-z_]+)\s*,\s*
|
||||
"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
|
||||
"#
|
||||
declare_clippy_lint!\s*[\{(]
|
||||
(?:\s+///.*)*
|
||||
\s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
|
||||
(?P<cat>[a-z_]+)\s*,\s*
|
||||
"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new(
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
static DEC_DEPRECATED_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
|
||||
Regex::new(
|
||||
r#"(?x)
|
||||
declare_deprecated_lint!\s*[{(]\s*
|
||||
(?:\s+///.*)*
|
||||
\s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
|
||||
"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
|
||||
"#
|
||||
declare_deprecated_lint!\s*[{(]\s*
|
||||
(?:\s+///.*)*
|
||||
\s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
|
||||
"(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap();
|
||||
}
|
||||
.unwrap()
|
||||
});
|
||||
static NL_ESCAPE_RE: SyncLazy<Regex> = SyncLazy::new(|| Regex::new(r#"\\\n\s*"#).unwrap());
|
||||
|
||||
pub static DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html";
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
|
||||
|
||||
use clap::{App, Arg, SubCommand};
|
||||
use clippy_dev::{fmt, new_lint, ra_setup, stderr_length_check, update_lints};
|
||||
use clippy_dev::{fmt, new_lint, ra_setup, serve, stderr_length_check, update_lints};
|
||||
|
||||
fn main() {
|
||||
let matches = App::new("Clippy developer tooling")
|
||||
|
@ -100,6 +100,19 @@ fn main() {
|
|||
.required(true),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("serve")
|
||||
.about("Launch a local 'ALL the Clippy Lints' website in a browser")
|
||||
.arg(
|
||||
Arg::with_name("port")
|
||||
.long("port")
|
||||
.short("p")
|
||||
.help("Local port for the http server")
|
||||
.default_value("8000")
|
||||
.validator_os(serve::validate_port),
|
||||
)
|
||||
.arg(Arg::with_name("lint").help("Which lint's page to load initially (optional)")),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
match matches.subcommand() {
|
||||
|
@ -129,6 +142,11 @@ fn main() {
|
|||
stderr_length_check::check();
|
||||
},
|
||||
("ra-setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")),
|
||||
("serve", Some(matches)) => {
|
||||
let port = matches.value_of("port").unwrap().parse().unwrap();
|
||||
let lint = matches.value_of("lint");
|
||||
serve::run(port, lint);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
|
64
clippy_dev/src/serve.rs
Normal file
64
clippy_dev/src/serve.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
use std::ffi::{OsStr, OsString};
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::thread;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
pub fn run(port: u16, lint: Option<&str>) -> ! {
|
||||
let mut url = Some(match lint {
|
||||
None => format!("http://localhost:{}", port),
|
||||
Some(lint) => format!("http://localhost:{}/#{}", port, lint),
|
||||
});
|
||||
|
||||
loop {
|
||||
if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") {
|
||||
Command::new("python3")
|
||||
.arg("util/export.py")
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.wait()
|
||||
.unwrap();
|
||||
}
|
||||
if let Some(url) = url.take() {
|
||||
thread::spawn(move || {
|
||||
Command::new("python3")
|
||||
.arg("-m")
|
||||
.arg("http.server")
|
||||
.arg(port.to_string())
|
||||
.current_dir("util/gh-pages")
|
||||
.spawn()
|
||||
.unwrap();
|
||||
// Give some time for python to start
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
// Launch browser after first export.py has completed and http.server is up
|
||||
let _ = opener::open(url);
|
||||
});
|
||||
}
|
||||
thread::sleep(Duration::from_millis(1000));
|
||||
}
|
||||
}
|
||||
|
||||
fn mtime(path: impl AsRef<Path>) -> SystemTime {
|
||||
let path = path.as_ref();
|
||||
if path.is_dir() {
|
||||
path.read_dir()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.flatten()
|
||||
.map(|entry| mtime(&entry.path()))
|
||||
.max()
|
||||
.unwrap_or(SystemTime::UNIX_EPOCH)
|
||||
} else {
|
||||
path.metadata()
|
||||
.and_then(|metadata| metadata.modified())
|
||||
.unwrap_or(SystemTime::UNIX_EPOCH)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::missing_errors_doc)]
|
||||
pub fn validate_port(arg: &OsStr) -> Result<(), OsString> {
|
||||
match arg.to_string_lossy().parse::<u16>() {
|
||||
Ok(_port) => Ok(()),
|
||||
Err(err) => Err(OsString::from(err.to_string())),
|
||||
}
|
||||
}
|
|
@ -20,7 +20,6 @@ edition = "2018"
|
|||
cargo_metadata = "0.11.1"
|
||||
if_chain = "1.0.0"
|
||||
itertools = "0.9"
|
||||
lazy_static = "1.0.2"
|
||||
pulldown-cmark = { version = "0.8", default-features = false }
|
||||
quine-mc_cluskey = "0.2.2"
|
||||
regex-syntax = "0.6"
|
||||
|
|
125
clippy_lints/src/asm_syntax.rs
Normal file
125
clippy_lints/src/asm_syntax.rs
Normal file
|
@ -0,0 +1,125 @@
|
|||
use std::fmt;
|
||||
|
||||
use crate::utils::span_lint_and_help;
|
||||
use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, Lint};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum AsmStyle {
|
||||
Intel,
|
||||
Att,
|
||||
}
|
||||
|
||||
impl fmt::Display for AsmStyle {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
AsmStyle::Intel => f.write_str("Intel"),
|
||||
AsmStyle::Att => f.write_str("AT&T"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Not for AsmStyle {
|
||||
type Output = AsmStyle;
|
||||
|
||||
fn not(self) -> AsmStyle {
|
||||
match self {
|
||||
AsmStyle::Intel => AsmStyle::Att,
|
||||
AsmStyle::Att => AsmStyle::Intel,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr_asm_syntax(lint: &'static Lint, cx: &EarlyContext<'_>, expr: &Expr, check_for: AsmStyle) {
|
||||
if let ExprKind::InlineAsm(ref inline_asm) = expr.kind {
|
||||
let style = if inline_asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
|
||||
AsmStyle::Att
|
||||
} else {
|
||||
AsmStyle::Intel
|
||||
};
|
||||
|
||||
if style == check_for {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
lint,
|
||||
expr.span,
|
||||
&format!("{} x86 assembly syntax used", style),
|
||||
None,
|
||||
&format!("use {} x86 assembly syntax", !style),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of Intel x86 assembly syntax.
|
||||
///
|
||||
/// **Why is this bad?** The lint has been enabled to indicate a preference
|
||||
/// for AT&T x86 assembly syntax.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # #![feature(asm)]
|
||||
/// # unsafe { let ptr = "".as_ptr();
|
||||
/// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
|
||||
/// # }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust,no_run
|
||||
/// # #![feature(asm)]
|
||||
/// # unsafe { let ptr = "".as_ptr();
|
||||
/// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
|
||||
/// # }
|
||||
/// ```
|
||||
pub INLINE_ASM_X86_INTEL_SYNTAX,
|
||||
restriction,
|
||||
"prefer AT&T x86 assembly syntax"
|
||||
}
|
||||
|
||||
declare_lint_pass!(InlineAsmX86IntelSyntax => [INLINE_ASM_X86_INTEL_SYNTAX]);
|
||||
|
||||
impl EarlyLintPass for InlineAsmX86IntelSyntax {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
check_expr_asm_syntax(Self::get_lints()[0], cx, expr, AsmStyle::Intel);
|
||||
}
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of AT&T x86 assembly syntax.
|
||||
///
|
||||
/// **Why is this bad?** The lint has been enabled to indicate a preference
|
||||
/// for Intel x86 assembly syntax.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # #![feature(asm)]
|
||||
/// # unsafe { let ptr = "".as_ptr();
|
||||
/// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
|
||||
/// # }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust,no_run
|
||||
/// # #![feature(asm)]
|
||||
/// # unsafe { let ptr = "".as_ptr();
|
||||
/// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
|
||||
/// # }
|
||||
/// ```
|
||||
pub INLINE_ASM_X86_ATT_SYNTAX,
|
||||
restriction,
|
||||
"prefer Intel x86 assembly syntax"
|
||||
}
|
||||
|
||||
declare_lint_pass!(InlineAsmX86AttSyntax => [INLINE_ASM_X86_ATT_SYNTAX]);
|
||||
|
||||
impl EarlyLintPass for InlineAsmX86AttSyntax {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
check_expr_asm_syntax(Self::get_lints()[0], cx, expr, AsmStyle::Att);
|
||||
}
|
||||
}
|
|
@ -137,17 +137,17 @@ declare_clippy_lint! {
|
|||
/// **Example:**
|
||||
/// ```rust
|
||||
/// // Good (as inner attribute)
|
||||
/// #![inline(always)]
|
||||
/// #![allow(dead_code)]
|
||||
///
|
||||
/// fn this_is_fine() { }
|
||||
///
|
||||
/// // Bad
|
||||
/// #[inline(always)]
|
||||
/// #[allow(dead_code)]
|
||||
///
|
||||
/// fn not_quite_good_code() { }
|
||||
///
|
||||
/// // Good (as outer attribute)
|
||||
/// #[inline(always)]
|
||||
/// #[allow(dead_code)]
|
||||
/// fn this_is_fine_too() { }
|
||||
/// ```
|
||||
pub EMPTY_LINE_AFTER_OUTER_ATTR,
|
||||
|
|
73
clippy_lints/src/disallowed_method.rs
Normal file
73
clippy_lints/src/disallowed_method.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use crate::utils::span_lint;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::Symbol;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Lints for specific trait methods defined in clippy.toml
|
||||
///
|
||||
/// **Why is this bad?** Some methods are undesirable in certain contexts,
|
||||
/// and it would be beneficial to lint for them as needed.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// // example code where clippy issues a warning
|
||||
/// foo.bad_method(); // Foo::bad_method is disallowed in the configuration
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust,ignore
|
||||
/// // example code which does not raise clippy warning
|
||||
/// goodStruct.bad_method(); // GoodStruct::bad_method is not disallowed
|
||||
/// ```
|
||||
pub DISALLOWED_METHOD,
|
||||
nursery,
|
||||
"use of a disallowed method call"
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DisallowedMethod {
|
||||
disallowed: FxHashSet<Vec<Symbol>>,
|
||||
}
|
||||
|
||||
impl DisallowedMethod {
|
||||
pub fn new(disallowed: &FxHashSet<String>) -> Self {
|
||||
Self {
|
||||
disallowed: disallowed
|
||||
.iter()
|
||||
.map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>())
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for DisallowedMethod {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::MethodCall(_path, _, _args, _) = &expr.kind {
|
||||
let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
|
||||
|
||||
let method_call = cx.get_def_path(def_id);
|
||||
if self.disallowed.contains(&method_call) {
|
||||
let method = method_call
|
||||
.iter()
|
||||
.map(|s| s.to_ident_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("::");
|
||||
|
||||
span_lint(
|
||||
cx,
|
||||
DISALLOWED_METHOD,
|
||||
expr.span,
|
||||
&format!("use of a disallowed method `{}`", method),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ use rustc_middle::ty::{self, Ty};
|
|||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_target::abi::LayoutOf;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
|
||||
|
||||
use crate::utils::span_lint;
|
||||
|
@ -60,12 +61,18 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
|
|||
fn check_fn(
|
||||
&mut self,
|
||||
cx: &LateContext<'tcx>,
|
||||
_: intravisit::FnKind<'tcx>,
|
||||
fn_kind: intravisit::FnKind<'tcx>,
|
||||
_: &'tcx FnDecl<'_>,
|
||||
body: &'tcx Body<'_>,
|
||||
_: Span,
|
||||
hir_id: HirId,
|
||||
) {
|
||||
if let Some(header) = fn_kind.header() {
|
||||
if header.abi != Abi::Rust {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the method is an impl for a trait, don't warn.
|
||||
let parent_id = cx.tcx.hir().get_parent_item(hir_id);
|
||||
let parent_node = cx.tcx.hir().find(parent_id);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(or_patterns)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
|
@ -153,6 +154,7 @@ mod utils;
|
|||
mod approx_const;
|
||||
mod arithmetic;
|
||||
mod as_conversions;
|
||||
mod asm_syntax;
|
||||
mod assertions_on_constants;
|
||||
mod assign_ops;
|
||||
mod async_yields_async;
|
||||
|
@ -176,6 +178,7 @@ mod dbg_macro;
|
|||
mod default_trait_access;
|
||||
mod dereference;
|
||||
mod derive;
|
||||
mod disallowed_method;
|
||||
mod doc;
|
||||
mod double_comparison;
|
||||
mod double_parens;
|
||||
|
@ -489,6 +492,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
&arithmetic::FLOAT_ARITHMETIC,
|
||||
&arithmetic::INTEGER_ARITHMETIC,
|
||||
&as_conversions::AS_CONVERSIONS,
|
||||
&asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
|
||||
&asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
|
||||
&assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
|
||||
&assign_ops::ASSIGN_OP_PATTERN,
|
||||
&assign_ops::MISREFACTORED_ASSIGN_OP,
|
||||
|
@ -529,6 +534,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
&derive::DERIVE_ORD_XOR_PARTIAL_ORD,
|
||||
&derive::EXPL_IMPL_CLONE_ON_COPY,
|
||||
&derive::UNSAFE_DERIVE_DESERIALIZE,
|
||||
&disallowed_method::DISALLOWED_METHOD,
|
||||
&doc::DOC_MARKDOWN,
|
||||
&doc::MISSING_ERRORS_DOC,
|
||||
&doc::MISSING_SAFETY_DOC,
|
||||
|
@ -851,9 +857,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
&types::UNIT_CMP,
|
||||
&types::UNNECESSARY_CAST,
|
||||
&types::VEC_BOX,
|
||||
&unicode::INVISIBLE_CHARACTERS,
|
||||
&unicode::NON_ASCII_LITERAL,
|
||||
&unicode::UNICODE_NOT_NFC,
|
||||
&unicode::ZERO_WIDTH_SPACE,
|
||||
&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
|
||||
&unnamed_address::FN_ADDRESS_COMPARISONS,
|
||||
&unnamed_address::VTABLE_ADDRESS_COMPARISONS,
|
||||
|
@ -1120,11 +1126,18 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
|
||||
store.register_late_pass(|| box manual_strip::ManualStrip);
|
||||
store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
|
||||
let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
|
||||
store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
|
||||
store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
|
||||
store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
|
||||
|
||||
|
||||
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
|
||||
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
|
||||
LintId::of(&arithmetic::INTEGER_ARITHMETIC),
|
||||
LintId::of(&as_conversions::AS_CONVERSIONS),
|
||||
LintId::of(&asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
|
||||
LintId::of(&asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
|
||||
LintId::of(&create_dir::CREATE_DIR),
|
||||
LintId::of(&dbg_macro::DBG_MACRO),
|
||||
LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
|
||||
|
@ -1159,6 +1172,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&shadow::SHADOW_REUSE),
|
||||
LintId::of(&shadow::SHADOW_SAME),
|
||||
LintId::of(&strings::STRING_ADD),
|
||||
LintId::of(&types::RC_BUFFER),
|
||||
LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT),
|
||||
LintId::of(&verbose_file_reads::VERBOSE_FILE_READS),
|
||||
LintId::of(&write::PRINT_STDOUT),
|
||||
|
@ -1463,7 +1477,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
|
||||
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
|
||||
LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
|
||||
LintId::of(&strings::STRING_LIT_AS_BYTES),
|
||||
LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
|
||||
LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
|
||||
LintId::of(&swap::ALMOST_SWAPPED),
|
||||
|
@ -1492,14 +1505,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&types::CHAR_LIT_AS_U8),
|
||||
LintId::of(&types::FN_TO_NUMERIC_CAST),
|
||||
LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
|
||||
LintId::of(&types::RC_BUFFER),
|
||||
LintId::of(&types::REDUNDANT_ALLOCATION),
|
||||
LintId::of(&types::TYPE_COMPLEXITY),
|
||||
LintId::of(&types::UNIT_ARG),
|
||||
LintId::of(&types::UNIT_CMP),
|
||||
LintId::of(&types::UNNECESSARY_CAST),
|
||||
LintId::of(&types::VEC_BOX),
|
||||
LintId::of(&unicode::ZERO_WIDTH_SPACE),
|
||||
LintId::of(&unicode::INVISIBLE_CHARACTERS),
|
||||
LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
|
||||
LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
|
||||
LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
|
||||
|
@ -1592,6 +1604,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED),
|
||||
LintId::of(&neg_multiply::NEG_MULTIPLY),
|
||||
LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT),
|
||||
LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
|
||||
LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
|
||||
LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
|
||||
LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES),
|
||||
LintId::of(&panic_unimplemented::PANIC_PARAMS),
|
||||
|
@ -1604,7 +1618,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&returns::LET_AND_RETURN),
|
||||
LintId::of(&returns::NEEDLESS_RETURN),
|
||||
LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
|
||||
LintId::of(&strings::STRING_LIT_AS_BYTES),
|
||||
LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
|
||||
LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME),
|
||||
LintId::of(&try_err::TRY_ERR),
|
||||
|
@ -1747,8 +1760,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&misc::FLOAT_CMP),
|
||||
LintId::of(&misc::MODULO_ONE),
|
||||
LintId::of(&mut_key::MUTABLE_KEY_TYPE),
|
||||
LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
|
||||
LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
|
||||
LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
|
||||
LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
|
||||
LintId::of(&ptr::MUT_FROM_REF),
|
||||
|
@ -1766,7 +1777,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
|
||||
LintId::of(&types::CAST_REF_TO_MUT),
|
||||
LintId::of(&types::UNIT_CMP),
|
||||
LintId::of(&unicode::ZERO_WIDTH_SPACE),
|
||||
LintId::of(&unicode::INVISIBLE_CHARACTERS),
|
||||
LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
|
||||
LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
|
||||
LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
|
||||
|
@ -1793,7 +1804,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
|
||||
LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
|
||||
LintId::of(&types::BOX_VEC),
|
||||
LintId::of(&types::RC_BUFFER),
|
||||
LintId::of(&types::REDUNDANT_ALLOCATION),
|
||||
LintId::of(&vec::USELESS_VEC),
|
||||
]);
|
||||
|
@ -1807,6 +1817,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
|
||||
LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
|
||||
LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY),
|
||||
LintId::of(&disallowed_method::DISALLOWED_METHOD),
|
||||
LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM),
|
||||
LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS),
|
||||
LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS),
|
||||
|
@ -1818,6 +1829,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(&needless_borrow::NEEDLESS_BORROW),
|
||||
LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
|
||||
LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE),
|
||||
LintId::of(&strings::STRING_LIT_AS_BYTES),
|
||||
LintId::of(&transmute::USELESS_TRANSMUTE),
|
||||
LintId::of(&use_self::USE_SELF),
|
||||
]);
|
||||
|
@ -1896,6 +1908,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
|
|||
ls.register_renamed("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles");
|
||||
ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles");
|
||||
ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion");
|
||||
ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
|
||||
}
|
||||
|
||||
// only exists to let the dogfood integration test works.
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
use crate::utils::paths;
|
||||
use crate::utils::{get_trait_def_id, in_macro, span_lint, trait_ref_of_method};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::{
|
||||
walk_fn_decl, walk_generic_param, walk_generics, walk_param_bound, walk_ty, NestedVisitorMap, Visitor,
|
||||
walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty,
|
||||
NestedVisitorMap, Visitor,
|
||||
};
|
||||
use rustc_hir::FnRetTy::Return;
|
||||
use rustc_hir::{
|
||||
BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item,
|
||||
ItemKind, Lifetime, LifetimeName, ParamName, QPath, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty,
|
||||
TyKind, WhereClause, WherePredicate,
|
||||
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem,
|
||||
ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier, TraitFn,
|
||||
TraitItem, TraitItemKind, Ty, TyKind, WhereClause, WherePredicate,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
|
||||
use crate::utils::{in_macro, last_path_segment, span_lint, trait_ref_of_method};
|
||||
use std::iter::FromIterator;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for lifetime annotations which can be removed by
|
||||
|
@ -25,8 +26,11 @@ declare_clippy_lint! {
|
|||
/// complicated, while there is nothing out of the ordinary going on. Removing
|
||||
/// them leads to more readable code.
|
||||
///
|
||||
/// **Known problems:** Potential false negatives: we bail out if the function
|
||||
/// has a `where` clause where lifetimes are mentioned.
|
||||
/// **Known problems:**
|
||||
/// - We bail out if the function has a `where` clause where lifetimes
|
||||
/// are mentioned due to potenial false positives.
|
||||
/// - Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the
|
||||
/// placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
|
@ -108,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
|
|||
}
|
||||
|
||||
/// The lifetime of a &-reference.
|
||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
|
||||
enum RefLt {
|
||||
Unnamed,
|
||||
Static,
|
||||
|
@ -127,7 +131,6 @@ fn check_fn_inner<'tcx>(
|
|||
return;
|
||||
}
|
||||
|
||||
let mut bounds_lts = Vec::new();
|
||||
let types = generics
|
||||
.params
|
||||
.iter()
|
||||
|
@ -156,13 +159,12 @@ fn check_fn_inner<'tcx>(
|
|||
if bound.name != LifetimeName::Static && !bound.is_elided() {
|
||||
return;
|
||||
}
|
||||
bounds_lts.push(bound);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if could_use_elision(cx, decl, body, &generics.params, bounds_lts) {
|
||||
if could_use_elision(cx, decl, body, &generics.params) {
|
||||
span_lint(
|
||||
cx,
|
||||
NEEDLESS_LIFETIMES,
|
||||
|
@ -181,7 +183,6 @@ fn could_use_elision<'tcx>(
|
|||
func: &'tcx FnDecl<'_>,
|
||||
body: Option<BodyId>,
|
||||
named_generics: &'tcx [GenericParam<'_>],
|
||||
bounds_lts: Vec<&'tcx Lifetime>,
|
||||
) -> bool {
|
||||
// There are two scenarios where elision works:
|
||||
// * no output references, all input references have different LT
|
||||
|
@ -204,15 +205,31 @@ fn could_use_elision<'tcx>(
|
|||
if let Return(ref ty) = func.output {
|
||||
output_visitor.visit_ty(ty);
|
||||
}
|
||||
for lt in named_generics {
|
||||
input_visitor.visit_generic_param(lt)
|
||||
}
|
||||
|
||||
let input_lts = match input_visitor.into_vec() {
|
||||
Some(lts) => lts_from_bounds(lts, bounds_lts.into_iter()),
|
||||
None => return false,
|
||||
};
|
||||
let output_lts = match output_visitor.into_vec() {
|
||||
Some(val) => val,
|
||||
None => return false,
|
||||
};
|
||||
if input_visitor.abort() || output_visitor.abort() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if allowed_lts
|
||||
.intersection(&FxHashSet::from_iter(
|
||||
input_visitor
|
||||
.nested_elision_site_lts
|
||||
.iter()
|
||||
.chain(output_visitor.nested_elision_site_lts.iter())
|
||||
.cloned()
|
||||
.filter(|v| matches!(v, RefLt::Named(_))),
|
||||
))
|
||||
.next()
|
||||
.is_some()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
let input_lts = input_visitor.lts;
|
||||
let output_lts = output_visitor.lts;
|
||||
|
||||
if let Some(body_id) = body {
|
||||
let mut checker = BodyLifetimeChecker {
|
||||
|
@ -277,27 +294,20 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
|
|||
allowed_lts
|
||||
}
|
||||
|
||||
fn lts_from_bounds<'a, T: Iterator<Item = &'a Lifetime>>(mut vec: Vec<RefLt>, bounds_lts: T) -> Vec<RefLt> {
|
||||
for lt in bounds_lts {
|
||||
if lt.name != LifetimeName::Static {
|
||||
vec.push(RefLt::Named(lt.name.ident().name));
|
||||
}
|
||||
}
|
||||
|
||||
vec
|
||||
}
|
||||
|
||||
/// Number of unique lifetimes in the given vector.
|
||||
#[must_use]
|
||||
fn unique_lifetimes(lts: &[RefLt]) -> usize {
|
||||
lts.iter().collect::<FxHashSet<_>>().len()
|
||||
}
|
||||
|
||||
const CLOSURE_TRAIT_BOUNDS: [&[&str]; 3] = [&paths::FN, &paths::FN_MUT, &paths::FN_ONCE];
|
||||
|
||||
/// A visitor usable for `rustc_front::visit::walk_ty()`.
|
||||
struct RefVisitor<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
lts: Vec<RefLt>,
|
||||
abort: bool,
|
||||
nested_elision_site_lts: Vec<RefLt>,
|
||||
unelided_trait_object_lifetime: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
|
||||
|
@ -305,7 +315,8 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
|
|||
Self {
|
||||
cx,
|
||||
lts: Vec::new(),
|
||||
abort: false,
|
||||
nested_elision_site_lts: Vec::new(),
|
||||
unelided_trait_object_lifetime: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -325,40 +336,16 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn into_vec(self) -> Option<Vec<RefLt>> {
|
||||
if self.abort {
|
||||
None
|
||||
} else {
|
||||
Some(self.lts)
|
||||
}
|
||||
fn all_lts(&self) -> Vec<RefLt> {
|
||||
self.lts
|
||||
.iter()
|
||||
.chain(self.nested_elision_site_lts.iter())
|
||||
.cloned()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn collect_anonymous_lifetimes(&mut self, qpath: &QPath<'_>, ty: &Ty<'_>) {
|
||||
if let Some(ref last_path_segment) = last_path_segment(qpath).args {
|
||||
if !last_path_segment.parenthesized
|
||||
&& !last_path_segment
|
||||
.args
|
||||
.iter()
|
||||
.any(|arg| matches!(arg, GenericArg::Lifetime(_)))
|
||||
{
|
||||
let hir_id = ty.hir_id;
|
||||
match self.cx.qpath_res(qpath, hir_id) {
|
||||
Res::Def(DefKind::TyAlias | DefKind::Struct, def_id) => {
|
||||
let generics = self.cx.tcx.generics_of(def_id);
|
||||
for _ in generics.params.as_slice() {
|
||||
self.record(&None);
|
||||
}
|
||||
},
|
||||
Res::Def(DefKind::Trait, def_id) => {
|
||||
let trait_def = self.cx.tcx.trait_def(def_id);
|
||||
for _ in &self.cx.tcx.generics_of(trait_def.def_id).params {
|
||||
self.record(&None);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn abort(&self) -> bool {
|
||||
self.unelided_trait_object_lifetime
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,30 +357,37 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
|
|||
self.record(&Some(*lifetime));
|
||||
}
|
||||
|
||||
fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>, tbm: TraitBoundModifier) {
|
||||
let trait_ref = &poly_tref.trait_ref;
|
||||
if CLOSURE_TRAIT_BOUNDS
|
||||
.iter()
|
||||
.any(|trait_path| trait_ref.trait_def_id() == get_trait_def_id(self.cx, trait_path))
|
||||
{
|
||||
let mut sub_visitor = RefVisitor::new(self.cx);
|
||||
sub_visitor.visit_trait_ref(trait_ref);
|
||||
self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
|
||||
} else {
|
||||
walk_poly_trait_ref(self, poly_tref, tbm);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
|
||||
match ty.kind {
|
||||
TyKind::Rptr(ref lt, _) if lt.is_elided() => {
|
||||
self.record(&None);
|
||||
},
|
||||
TyKind::Path(ref path) => {
|
||||
self.collect_anonymous_lifetimes(path, ty);
|
||||
},
|
||||
TyKind::OpaqueDef(item, _) => {
|
||||
let map = self.cx.tcx.hir();
|
||||
if let ItemKind::OpaqueTy(ref exist_ty) = map.expect_item(item.id).kind {
|
||||
for bound in exist_ty.bounds {
|
||||
if let GenericBound::Outlives(_) = *bound {
|
||||
self.record(&None);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
let item = map.expect_item(item.id);
|
||||
walk_item(self, item);
|
||||
walk_ty(self, ty);
|
||||
},
|
||||
TyKind::BareFn(&BareFnTy { decl, .. }) => {
|
||||
let mut sub_visitor = RefVisitor::new(self.cx);
|
||||
sub_visitor.visit_fn_decl(decl);
|
||||
self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
|
||||
return;
|
||||
},
|
||||
TyKind::TraitObject(bounds, ref lt) => {
|
||||
if !lt.is_elided() {
|
||||
self.abort = true;
|
||||
self.unelided_trait_object_lifetime = true;
|
||||
}
|
||||
for bound in bounds {
|
||||
self.visit_poly_trait_ref(bound, TraitBoundModifier::None);
|
||||
|
@ -430,16 +424,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereCl
|
|||
walk_param_bound(&mut visitor, bound);
|
||||
}
|
||||
// and check that all lifetimes are allowed
|
||||
match visitor.into_vec() {
|
||||
None => return false,
|
||||
Some(lts) => {
|
||||
for lt in lts {
|
||||
if !allowed_lts.contains(<) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
return visitor.all_lts().iter().any(|it| !allowed_lts.contains(it));
|
||||
},
|
||||
WherePredicate::EqPredicate(ref pred) => {
|
||||
let mut visitor = RefVisitor::new(cx);
|
||||
|
|
|
@ -264,13 +264,10 @@ impl LiteralDigitGrouping {
|
|||
|
||||
let (part, mistyped_suffixes, missing_char) = if let Some((_, exponent)) = &mut num_lit.exponent {
|
||||
(exponent, &["32", "64"][..], 'f')
|
||||
} else if num_lit.fraction.is_some() {
|
||||
(&mut num_lit.integer, &["32", "64"][..], 'f')
|
||||
} else {
|
||||
num_lit
|
||||
.fraction
|
||||
.as_mut()
|
||||
.map_or((&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i'), |fraction| {
|
||||
(fraction, &["32", "64"][..], 'f')
|
||||
})
|
||||
(&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i')
|
||||
};
|
||||
|
||||
let mut split = part.rsplit('_');
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::utils::paths;
|
|||
use crate::utils::sugg::Sugg;
|
||||
use crate::utils::usage::{is_unused, mutated_variables};
|
||||
use crate::utils::{
|
||||
get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
|
||||
contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
|
||||
is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment, match_trait_method,
|
||||
match_type, match_var, multispan_sugg, qpath_res, snippet, snippet_opt, snippet_with_applicability,
|
||||
snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg,
|
||||
|
@ -1276,6 +1276,8 @@ fn check_for_loop_range<'tcx>(
|
|||
|
||||
let skip = if starts_at_zero {
|
||||
String::new()
|
||||
} else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start) {
|
||||
return;
|
||||
} else {
|
||||
format!(".skip({})", snippet(cx, start.span, ".."))
|
||||
};
|
||||
|
@ -1302,6 +1304,8 @@ fn check_for_loop_range<'tcx>(
|
|||
|
||||
if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) {
|
||||
String::new()
|
||||
} else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr) {
|
||||
return;
|
||||
} else {
|
||||
match limits {
|
||||
ast::RangeLimits::Closed => {
|
||||
|
@ -2134,7 +2138,7 @@ enum VarState {
|
|||
DontWarn,
|
||||
}
|
||||
|
||||
/// Scan a for loop for variables that are incremented exactly once.
|
||||
/// Scan a for loop for variables that are incremented exactly once and not used after that.
|
||||
struct IncrementVisitor<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>, // context reference
|
||||
states: FxHashMap<HirId, VarState>, // incremented variables
|
||||
|
@ -2154,6 +2158,10 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
|
|||
if let Some(def_id) = var_def_id(self.cx, expr) {
|
||||
if let Some(parent) = get_parent_expr(self.cx, expr) {
|
||||
let state = self.states.entry(def_id).or_insert(VarState::Initial);
|
||||
if *state == VarState::IncrOnce {
|
||||
*state = VarState::DontWarn;
|
||||
return;
|
||||
}
|
||||
|
||||
match parent.kind {
|
||||
ExprKind::AssignOp(op, ref lhs, ref rhs) => {
|
||||
|
|
|
@ -18,9 +18,9 @@ declare_clippy_lint! {
|
|||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// ```rust,ignore
|
||||
/// #[macro_use]
|
||||
/// use lazy_static;
|
||||
/// use some_macro;
|
||||
/// ```
|
||||
pub MACRO_USE_IMPORTS,
|
||||
pedantic,
|
||||
|
|
|
@ -400,8 +400,8 @@ declare_clippy_lint! {
|
|||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `_.map(_).flatten(_)`,
|
||||
///
|
||||
/// **Why is this bad?** Readability, this can be written more concisely as a
|
||||
/// single method call using `_.flat_map(_)`
|
||||
/// **Why is this bad?** Readability, this can be written more concisely as
|
||||
/// `_.flat_map(_)`
|
||||
///
|
||||
/// **Known problems:**
|
||||
///
|
||||
|
@ -424,8 +424,8 @@ declare_clippy_lint! {
|
|||
/// **What it does:** Checks for usage of `_.filter(_).map(_)`,
|
||||
/// `_.filter(_).flat_map(_)`, `_.filter_map(_).flat_map(_)` and similar.
|
||||
///
|
||||
/// **Why is this bad?** Readability, this can be written more concisely as a
|
||||
/// single method call.
|
||||
/// **Why is this bad?** Readability, this can be written more concisely as
|
||||
/// `_.filter_map(_)`.
|
||||
///
|
||||
/// **Known problems:** Often requires a condition + Option/Iterator creation
|
||||
/// inside the closure.
|
||||
|
@ -452,8 +452,8 @@ declare_clippy_lint! {
|
|||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `_.filter_map(_).next()`.
|
||||
///
|
||||
/// **Why is this bad?** Readability, this can be written more concisely as a
|
||||
/// single method call.
|
||||
/// **Why is this bad?** Readability, this can be written more concisely as
|
||||
/// `_.find_map(_)`.
|
||||
///
|
||||
/// **Known problems:** None
|
||||
///
|
||||
|
@ -496,8 +496,8 @@ declare_clippy_lint! {
|
|||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `_.find(_).map(_)`.
|
||||
///
|
||||
/// **Why is this bad?** Readability, this can be written more concisely as a
|
||||
/// single method call.
|
||||
/// **Why is this bad?** Readability, this can be written more concisely as
|
||||
/// `_.find_map(_)`.
|
||||
///
|
||||
/// **Known problems:** Often requires a condition + Option/Iterator creation
|
||||
/// inside the closure.
|
||||
|
@ -1276,8 +1276,8 @@ declare_clippy_lint! {
|
|||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
|
||||
///
|
||||
/// **Why is this bad?** Readability, this can be written more concisely as a
|
||||
/// single method call.
|
||||
/// **Why is this bad?** Readability, this can be written more concisely as
|
||||
/// `_.as_deref()`.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
|
@ -1668,9 +1668,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
|||
if let ty::Opaque(def_id, _) = *ret_ty.kind() {
|
||||
// one of the associated types must be Self
|
||||
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
|
||||
if let ty::PredicateAtom::Projection(projection_predicate) =
|
||||
predicate.skip_binders()
|
||||
{
|
||||
if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() {
|
||||
// walk the associated type and check for Self
|
||||
if contains_ty(projection_predicate.ty, self_ty) {
|
||||
return;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use crate::utils::qualify_min_const_fn::is_min_const_fn;
|
||||
use crate::utils::{fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use crate::utils::qualify_min_const_fn::is_min_const_fn;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::Span;
|
||||
use rustc_typeck::hir_ty_to_ty;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::utils::span_lint_and_sugg;
|
||||
use crate::utils::{in_macro, span_lint_and_sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -69,11 +69,30 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
|
|||
if let [segment] = &path.segments[..];
|
||||
if segment.ident.name == kw::SelfUpper;
|
||||
then {
|
||||
// In case we have a named lifetime, we check if the name comes from expansion.
|
||||
// If it does, at this point we know the rest of the parameter was written by the user,
|
||||
// so let them decide what the name of the lifetime should be.
|
||||
// See #6089 for more details.
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let self_param = match (binding_mode, mutbl) {
|
||||
(Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(),
|
||||
(Mode::Ref(Some(lifetime)), Mutability::Mut) => format!("&{} mut self", &lifetime.ident.name),
|
||||
(Mode::Ref(Some(lifetime)), Mutability::Mut) => {
|
||||
if in_macro(lifetime.ident.span) {
|
||||
applicability = Applicability::HasPlaceholders;
|
||||
"&'_ mut self".to_string()
|
||||
} else {
|
||||
format!("&{} mut self", &lifetime.ident.name)
|
||||
}
|
||||
},
|
||||
(Mode::Ref(None), Mutability::Not) => "&self".to_string(),
|
||||
(Mode::Ref(Some(lifetime)), Mutability::Not) => format!("&{} self", &lifetime.ident.name),
|
||||
(Mode::Ref(Some(lifetime)), Mutability::Not) => {
|
||||
if in_macro(lifetime.ident.span) {
|
||||
applicability = Applicability::HasPlaceholders;
|
||||
"&'_ self".to_string()
|
||||
} else {
|
||||
format!("&{} self", &lifetime.ident.name)
|
||||
}
|
||||
},
|
||||
(Mode::Value, Mutability::Mut) => "mut self".to_string(),
|
||||
(Mode::Value, Mutability::Not) => "self".to_string(),
|
||||
};
|
||||
|
@ -85,7 +104,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
|
|||
"the type of the `self` parameter does not need to be arbitrary",
|
||||
"consider to change this parameter to",
|
||||
self_param,
|
||||
Applicability::MachineApplicable,
|
||||
applicability,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +112,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
|
|||
|
||||
impl EarlyLintPass for NeedlessArbitrarySelfType {
|
||||
fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
|
||||
if !p.is_self() {
|
||||
// Bail out if the parameter it's not a receiver or was not written by the user
|
||||
if !p.is_self() || in_macro(p.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Checks for uses of const which the type is not `Freeze` (`Cell`-free).
|
||||
//!
|
||||
//! This lint is **deny** by default.
|
||||
//! This lint is **warn** by default.
|
||||
|
||||
use std::ptr;
|
||||
|
||||
|
@ -17,6 +17,8 @@ use rustc_typeck::hir_ty_to_ty;
|
|||
use crate::utils::{in_constant, qpath_res, span_lint_and_then};
|
||||
use if_chain::if_chain;
|
||||
|
||||
// FIXME: this is a correctness problem but there's no suitable
|
||||
// warn-by-default category.
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for declaration of `const` items which is interior
|
||||
/// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.).
|
||||
|
@ -34,6 +36,15 @@ declare_clippy_lint! {
|
|||
/// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
|
||||
/// and this lint should be suppressed.
|
||||
///
|
||||
/// When an enum has variants with interior mutability, use of its non interior mutable
|
||||
/// variants can generate false positives. See issue
|
||||
/// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962)
|
||||
///
|
||||
/// Types that have underlying or potential interior mutability trigger the lint whether
|
||||
/// the interior mutable field is used or not. See issues
|
||||
/// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
|
||||
/// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825)
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||
|
@ -49,10 +60,12 @@ declare_clippy_lint! {
|
|||
/// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
|
||||
/// ```
|
||||
pub DECLARE_INTERIOR_MUTABLE_CONST,
|
||||
correctness,
|
||||
style,
|
||||
"declaring `const` with interior mutability"
|
||||
}
|
||||
|
||||
// FIXME: this is a correctness problem but there's no suitable
|
||||
// warn-by-default category.
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks if `const` items which is interior mutable (e.g.,
|
||||
/// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly.
|
||||
|
@ -64,7 +77,14 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// The `const` value should be stored inside a `static` item.
|
||||
///
|
||||
/// **Known problems:** None
|
||||
/// **Known problems:** When an enum has variants with interior mutability, use of its non
|
||||
/// interior mutable variants can generate false positives. See issue
|
||||
/// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962)
|
||||
///
|
||||
/// Types that have underlying or potential interior mutability trigger the lint whether
|
||||
/// the interior mutable field is used or not. See issues
|
||||
/// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
|
||||
/// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825)
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
|
@ -81,7 +101,7 @@ declare_clippy_lint! {
|
|||
/// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
|
||||
/// ```
|
||||
pub BORROW_INTERIOR_MUTABLE_CONST,
|
||||
correctness,
|
||||
style,
|
||||
"referencing `const` with interior mutability"
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ fn check_set<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
|
|||
|
||||
fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
|
||||
let mut parser = regex_syntax::ParserBuilder::new()
|
||||
.unicode(utf8)
|
||||
.unicode(true)
|
||||
.allow_invalid_utf8(!utf8)
|
||||
.build();
|
||||
|
||||
|
|
|
@ -69,7 +69,27 @@ declare_clippy_lint! {
|
|||
/// **Why is this bad?** Byte string literals (e.g., `b"foo"`) can be used
|
||||
/// instead. They are shorter but less discoverable than `as_bytes()`.
|
||||
///
|
||||
/// **Known Problems:** None.
|
||||
/// **Known Problems:**
|
||||
/// `"str".as_bytes()` and the suggested replacement of `b"str"` are not
|
||||
/// equivalent because they have different types. The former is `&[u8]`
|
||||
/// while the latter is `&[u8; 3]`. That means in general they will have a
|
||||
/// different set of methods and different trait implementations.
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// fn f(v: Vec<u8>) {}
|
||||
///
|
||||
/// f("...".as_bytes().to_owned()); // works
|
||||
/// f(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec<u8>
|
||||
///
|
||||
/// fn g(r: impl std::io::Read) {}
|
||||
///
|
||||
/// g("...".as_bytes()); // works
|
||||
/// g(b"..."); // does not work
|
||||
/// ```
|
||||
///
|
||||
/// The actual equivalent of `"str".as_bytes()` with the same type is not
|
||||
/// `b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not
|
||||
/// more readable than a function call.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
|
@ -80,7 +100,7 @@ declare_clippy_lint! {
|
|||
/// let bs = b"a byte string";
|
||||
/// ```
|
||||
pub STRING_LIT_AS_BYTES,
|
||||
style,
|
||||
nursery,
|
||||
"calling `as_bytes` on a string literal instead of using a byte string literal"
|
||||
}
|
||||
|
||||
|
|
|
@ -216,18 +216,19 @@ declare_clippy_lint! {
|
|||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for Rc<T> and Arc<T> when T is a mutable buffer type such as String or Vec
|
||||
/// **What it does:** Checks for `Rc<T>` and `Arc<T>` when `T` is a mutable buffer type such as `String` or `Vec`.
|
||||
///
|
||||
/// **Why is this bad?** Expressions such as Rc<String> have no advantage over Rc<str>, since
|
||||
/// it is larger and involves an extra level of indirection, and doesn't implement Borrow<str>.
|
||||
/// **Why is this bad?** Expressions such as `Rc<String>` usually have no advantage over `Rc<str>`, since
|
||||
/// it is larger and involves an extra level of indirection, and doesn't implement `Borrow<str>`.
|
||||
///
|
||||
/// While mutating a buffer type would still be possible with Rc::get_mut(), it only
|
||||
/// works if there are no additional references yet, which defeats the purpose of
|
||||
/// While mutating a buffer type would still be possible with `Rc::get_mut()`, it only
|
||||
/// works if there are no additional references yet, which usually defeats the purpose of
|
||||
/// enclosing it in a shared ownership type. Instead, additionally wrapping the inner
|
||||
/// type with an interior mutable container (such as RefCell or Mutex) would normally
|
||||
/// type with an interior mutable container (such as `RefCell` or `Mutex`) would normally
|
||||
/// be used.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
/// **Known problems:** This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for
|
||||
/// cases where mutation only happens before there are any additional references.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust,ignore
|
||||
|
@ -241,7 +242,7 @@ declare_clippy_lint! {
|
|||
/// fn foo(interned: Rc<str>) { ... }
|
||||
/// ```
|
||||
pub RC_BUFFER,
|
||||
perf,
|
||||
restriction,
|
||||
"shared ownership of a buffer type"
|
||||
}
|
||||
|
||||
|
|
|
@ -8,18 +8,18 @@ use rustc_span::source_map::Span;
|
|||
use unicode_normalization::UnicodeNormalization;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for the Unicode zero-width space in the code.
|
||||
/// **What it does:** Checks for invisible Unicode characters in the code.
|
||||
///
|
||||
/// **Why is this bad?** Having an invisible character in the code makes for all
|
||||
/// sorts of April fools, but otherwise is very much frowned upon.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:** You don't see it, but there may be a zero-width space
|
||||
/// somewhere in this text.
|
||||
pub ZERO_WIDTH_SPACE,
|
||||
/// **Example:** You don't see it, but there may be a zero-width space or soft hyphen
|
||||
/// somewhere in this text.
|
||||
pub INVISIBLE_CHARACTERS,
|
||||
correctness,
|
||||
"using a zero-width space in a string literal, which is confusing"
|
||||
"using an invisible character in a string literal, which is confusing"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
@ -63,7 +63,7 @@ declare_clippy_lint! {
|
|||
"using a Unicode literal not in NFC normal form (see [Unicode tr15](http://www.unicode.org/reports/tr15/) for further information)"
|
||||
}
|
||||
|
||||
declare_lint_pass!(Unicode => [ZERO_WIDTH_SPACE, NON_ASCII_LITERAL, UNICODE_NOT_NFC]);
|
||||
declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_NOT_NFC]);
|
||||
|
||||
impl LateLintPass<'_> for Unicode {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
|
||||
|
@ -91,14 +91,17 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String {
|
|||
|
||||
fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
|
||||
let string = snippet(cx, span, "");
|
||||
if string.contains('\u{200B}') {
|
||||
if string.chars().any(|c| ['\u{200B}', '\u{ad}', '\u{2060}'].contains(&c)) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
ZERO_WIDTH_SPACE,
|
||||
INVISIBLE_CHARACTERS,
|
||||
span,
|
||||
"zero-width space detected",
|
||||
"invisible character detected",
|
||||
"consider replacing the string with",
|
||||
string.replace("\u{200B}", "\\u{200B}"),
|
||||
string
|
||||
.replace("\u{200B}", "\\u{200B}")
|
||||
.replace("\u{ad}", "\\u{AD}")
|
||||
.replace("\u{2060}", "\\u{2060}"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -170,22 +170,12 @@ fn mirrored_exprs(
|
|||
}
|
||||
|
||||
fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
|
||||
// NOTE: Vectors of references are not supported. In order to avoid hitting https://github.com/rust-lang/rust/issues/34162,
|
||||
// (different unnamed lifetimes for closure arg and return type) we need to make sure the suggested
|
||||
// closure parameter is not a reference in case we suggest `Reverse`. Trying to destructure more
|
||||
// than one level of references would add some extra complexity as we would have to compensate
|
||||
// in the closure body.
|
||||
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
|
||||
if let name = name_ident.ident.name.to_ident_string();
|
||||
if name == "sort_by" || name == "sort_unstable_by";
|
||||
if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
|
||||
let vec_ty = cx.typeck_results().expr_ty(vec);
|
||||
if utils::is_type_diagnostic_item(cx, vec_ty, sym!(vec_type));
|
||||
let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); // T in Vec<T>
|
||||
if !matches!(&ty.kind(), ty::Ref(..));
|
||||
if utils::is_copy(cx, ty);
|
||||
if utils::is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym!(vec_type));
|
||||
if let closure_body = cx.tcx.hir().body(*closure_body_id);
|
||||
if let &[
|
||||
Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
|
||||
|
@ -210,40 +200,32 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
|
|||
let vec_name = Sugg::hir(cx, &args[0], "..").to_string();
|
||||
let unstable = name == "sort_unstable_by";
|
||||
|
||||
if_chain! {
|
||||
if let ExprKind::Path(QPath::Resolved(_, Path {
|
||||
segments: [PathSegment { ident: left_name, .. }], ..
|
||||
})) = &left_expr.kind;
|
||||
if left_name == left_ident;
|
||||
then {
|
||||
return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }))
|
||||
} else {
|
||||
if !key_returns_borrow(cx, left_expr) {
|
||||
return Some(LintTrigger::SortByKey(SortByKeyDetection {
|
||||
vec_name,
|
||||
unstable,
|
||||
closure_arg,
|
||||
closure_body,
|
||||
reverse
|
||||
}))
|
||||
}
|
||||
if let ExprKind::Path(QPath::Resolved(_, Path {
|
||||
segments: [PathSegment { ident: left_name, .. }], ..
|
||||
})) = &left_expr.kind {
|
||||
if left_name == left_ident {
|
||||
return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }));
|
||||
}
|
||||
}
|
||||
|
||||
if !expr_borrows(cx, left_expr) {
|
||||
return Some(LintTrigger::SortByKey(SortByKeyDetection {
|
||||
vec_name,
|
||||
unstable,
|
||||
closure_arg,
|
||||
closure_body,
|
||||
reverse
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn key_returns_borrow(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
if let Some(def_id) = utils::fn_def_id(cx, expr) {
|
||||
let output = cx.tcx.fn_sig(def_id).output();
|
||||
let ty = output.skip_binder();
|
||||
return matches!(ty.kind(), ty::Ref(..))
|
||||
|| ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
|
||||
}
|
||||
|
||||
false
|
||||
fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
|
||||
}
|
||||
|
||||
impl LateLintPass<'_> for UnnecessarySortBy {
|
||||
|
@ -256,7 +238,7 @@ impl LateLintPass<'_> for UnnecessarySortBy {
|
|||
"use Vec::sort_by_key here instead",
|
||||
"try",
|
||||
format!(
|
||||
"{}.sort{}_by_key(|&{}| {})",
|
||||
"{}.sort{}_by_key(|{}| {})",
|
||||
trigger.vec_name,
|
||||
if trigger.unstable { "_unstable" } else { "" },
|
||||
trigger.closure_arg,
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
#![deny(clippy::missing_docs_in_private_items)]
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use rustc_ast::ast::{LitKind, MetaItemKind, NestedMetaItem};
|
||||
use rustc_span::source_map;
|
||||
use source_map::Span;
|
||||
use std::lazy::SyncLazy;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Mutex;
|
||||
use std::{env, fmt, fs, io};
|
||||
|
@ -54,9 +54,8 @@ impl From<io::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref ERRORS: Mutex<Vec<Error>> = Mutex::new(Vec::new());
|
||||
}
|
||||
/// Vec of errors that might be collected during config toml parsing
|
||||
static ERRORS: SyncLazy<Mutex<Vec<Error>>> = SyncLazy::new(|| Mutex::new(Vec::new()));
|
||||
|
||||
macro_rules! define_Conf {
|
||||
($(#[$doc:meta] ($config:ident, $config_str:literal: $Ty:ty, $default:expr),)+) => {
|
||||
|
@ -82,6 +81,7 @@ macro_rules! define_Conf {
|
|||
use serde::Deserialize;
|
||||
pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<$Ty, D::Error> {
|
||||
use super::super::{ERRORS, Error};
|
||||
|
||||
Ok(
|
||||
<$Ty>::deserialize(deserializer).unwrap_or_else(|e| {
|
||||
ERRORS
|
||||
|
@ -164,6 +164,8 @@ define_Conf! {
|
|||
(max_fn_params_bools, "max_fn_params_bools": u64, 3),
|
||||
/// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
|
||||
(warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false),
|
||||
/// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses
|
||||
(disallowed_methods, "disallowed_methods": Vec<String>, Vec::<String>::new()),
|
||||
}
|
||||
|
||||
impl Default for Conf {
|
||||
|
|
|
@ -18,9 +18,9 @@ pub mod internal_lints;
|
|||
pub mod numeric_literal;
|
||||
pub mod paths;
|
||||
pub mod ptr;
|
||||
pub mod qualify_min_const_fn;
|
||||
pub mod sugg;
|
||||
pub mod usage;
|
||||
pub mod qualify_min_const_fn;
|
||||
|
||||
pub use self::attrs::*;
|
||||
pub use self::diagnostics::*;
|
||||
|
@ -47,7 +47,6 @@ use rustc_lint::{LateContext, Level, Lint, LintContext};
|
|||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
|
||||
use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_mir::const_eval;
|
||||
use rustc_span::hygiene::{ExpnKind, MacroKind};
|
||||
use rustc_span::source_map::original_sp;
|
||||
use rustc_span::symbol::{self, kw, Symbol};
|
||||
|
@ -884,19 +883,11 @@ pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
|
||||
/// Checks if an expression is constructing a tuple-like enum variant or struct
|
||||
pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
fn has_no_arguments(cx: &LateContext<'_>, def_id: DefId) -> bool {
|
||||
cx.tcx.fn_sig(def_id).skip_binder().inputs().is_empty()
|
||||
}
|
||||
|
||||
if let ExprKind::Call(ref fun, _) = expr.kind {
|
||||
if let ExprKind::Path(ref qp) = fun.kind {
|
||||
let res = cx.qpath_res(qp, fun.hir_id);
|
||||
return match res {
|
||||
def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
|
||||
// FIXME: check the constness of the arguments, see https://github.com/rust-lang/rust-clippy/pull/5682#issuecomment-638681210
|
||||
def::Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) if has_no_arguments(cx, def_id) => {
|
||||
const_eval::is_const_fn(cx.tcx, def_id)
|
||||
},
|
||||
def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
|
||||
_ => false,
|
||||
};
|
||||
|
@ -1287,8 +1278,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
|||
ty::Opaque(ref def_id, _) => {
|
||||
for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
|
||||
if let ty::PredicateAtom::Trait(trait_predicate, _) = predicate.skip_binders() {
|
||||
if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some()
|
||||
{
|
||||
if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,8 +36,9 @@ pub struct NumericLiteral<'a> {
|
|||
pub integer: &'a str,
|
||||
/// The fraction part of the number.
|
||||
pub fraction: Option<&'a str>,
|
||||
/// The character used as exponent separator (b'e' or b'E') and the exponent part.
|
||||
pub exponent: Option<(char, &'a str)>,
|
||||
/// The exponent separator (b'e' or b'E') including preceding underscore if present
|
||||
/// and the exponent part.
|
||||
pub exponent: Option<(&'a str, &'a str)>,
|
||||
|
||||
/// The type suffix, including preceding underscore if present.
|
||||
pub suffix: Option<&'a str>,
|
||||
|
@ -100,7 +101,7 @@ impl<'a> NumericLiteral<'a> {
|
|||
self.radix == Radix::Decimal
|
||||
}
|
||||
|
||||
pub fn split_digit_parts(digits: &str, float: bool) -> (&str, Option<&str>, Option<(char, &str)>) {
|
||||
pub fn split_digit_parts(digits: &str, float: bool) -> (&str, Option<&str>, Option<(&str, &str)>) {
|
||||
let mut integer = digits;
|
||||
let mut fraction = None;
|
||||
let mut exponent = None;
|
||||
|
@ -113,12 +114,14 @@ impl<'a> NumericLiteral<'a> {
|
|||
fraction = Some(&digits[i + 1..]);
|
||||
},
|
||||
'e' | 'E' => {
|
||||
if integer.len() > i {
|
||||
integer = &digits[..i];
|
||||
let exp_start = if digits[..i].ends_with('_') { i - 1 } else { i };
|
||||
|
||||
if integer.len() > exp_start {
|
||||
integer = &digits[..exp_start];
|
||||
} else {
|
||||
fraction = Some(&digits[integer.len() + 1..i]);
|
||||
fraction = Some(&digits[integer.len() + 1..exp_start]);
|
||||
};
|
||||
exponent = Some((c, &digits[i + 1..]));
|
||||
exponent = Some((&digits[exp_start..=i], &digits[i + 1..]));
|
||||
break;
|
||||
},
|
||||
_ => {},
|
||||
|
@ -153,7 +156,7 @@ impl<'a> NumericLiteral<'a> {
|
|||
}
|
||||
|
||||
if let Some((separator, exponent)) = self.exponent {
|
||||
output.push(separator);
|
||||
output.push_str(separator);
|
||||
Self::group_digits(&mut output, exponent, group_size, true, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
|
|||
pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
|
||||
pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
|
||||
pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
|
||||
pub const FN: [&str; 3] = ["core", "ops", "Fn"];
|
||||
pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"];
|
||||
pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"];
|
||||
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
|
||||
pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
|
||||
pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::mir::{
|
||||
Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
|
||||
TerminatorKind,
|
||||
};
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
|
||||
use rustc_span::symbol::{sym};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::spec::abi::Abi::RustIntrinsic;
|
||||
use std::borrow::Cow;
|
||||
|
@ -24,15 +27,9 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>) -> McfResult {
|
|||
| ty::PredicateAtom::ConstEvaluatable(..)
|
||||
| ty::PredicateAtom::ConstEquate(..)
|
||||
| ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue,
|
||||
ty::PredicateAtom::ObjectSafe(_) => {
|
||||
panic!("object safe predicate on function: {:#?}", predicate)
|
||||
}
|
||||
ty::PredicateAtom::ClosureKind(..) => {
|
||||
panic!("closure kind predicate on function: {:#?}", predicate)
|
||||
}
|
||||
ty::PredicateAtom::Subtype(_) => {
|
||||
panic!("subtype predicate on function: {:#?}", predicate)
|
||||
}
|
||||
ty::PredicateAtom::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
|
||||
ty::PredicateAtom::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
|
||||
ty::PredicateAtom::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
|
||||
ty::PredicateAtom::Trait(pred, _) => {
|
||||
if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
|
||||
continue;
|
||||
|
@ -48,12 +45,12 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>) -> McfResult {
|
|||
on const fn parameters are unstable"
|
||||
.into(),
|
||||
));
|
||||
}
|
||||
},
|
||||
// other kinds of bounds are either tautologies
|
||||
// or cause errors in other passes
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
match predicates.parent {
|
||||
|
@ -93,24 +90,23 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult {
|
|||
|
||||
match ty.kind() {
|
||||
ty::Ref(_, _, hir::Mutability::Mut) => {
|
||||
return Err((span, "mutable references in const fn are unstable".into()));
|
||||
}
|
||||
return Err((span, "mutable references in const fn are unstable".into()));
|
||||
},
|
||||
ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
|
||||
ty::FnPtr(..) => {
|
||||
return Err((span, "function pointers in const fn are unstable".into()));
|
||||
}
|
||||
return Err((span, "function pointers in const fn are unstable".into()));
|
||||
},
|
||||
ty::Dynamic(preds, _) => {
|
||||
for pred in preds.iter() {
|
||||
match pred.skip_binder() {
|
||||
ty::ExistentialPredicate::AutoTrait(_)
|
||||
| ty::ExistentialPredicate::Projection(_) => {
|
||||
ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => {
|
||||
return Err((
|
||||
span,
|
||||
"trait bounds other than `Sized` \
|
||||
on const fn parameters are unstable"
|
||||
.into(),
|
||||
));
|
||||
}
|
||||
},
|
||||
ty::ExistentialPredicate::Trait(trait_ref) => {
|
||||
if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
|
||||
return Err((
|
||||
|
@ -120,34 +116,23 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult {
|
|||
.into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_rvalue(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
def_id: DefId,
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
span: Span,
|
||||
) -> McfResult {
|
||||
fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rvalue<'tcx>, span: Span) -> McfResult {
|
||||
match rvalue {
|
||||
Rvalue::ThreadLocalRef(_) => {
|
||||
Err((span, "cannot access thread local storage in const fn".into()))
|
||||
}
|
||||
Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
|
||||
check_operand(tcx, operand, span, body)
|
||||
}
|
||||
Rvalue::Len(place)
|
||||
| Rvalue::Discriminant(place)
|
||||
| Rvalue::Ref(_, _, place)
|
||||
| Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, body),
|
||||
Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
|
||||
Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => check_operand(tcx, operand, span, body),
|
||||
Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
|
||||
check_place(tcx, *place, span, body)
|
||||
},
|
||||
Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
|
||||
use rustc_middle::ty::cast::CastTy;
|
||||
let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast");
|
||||
|
@ -155,20 +140,16 @@ fn check_rvalue(
|
|||
match (cast_in, cast_out) {
|
||||
(CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
|
||||
Err((span, "casting pointers to ints is unstable in const fn".into()))
|
||||
}
|
||||
},
|
||||
_ => check_operand(tcx, operand, span, body),
|
||||
}
|
||||
}
|
||||
Rvalue::Cast(
|
||||
CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
|
||||
operand,
|
||||
_,
|
||||
) => check_operand(tcx, operand, span, body),
|
||||
},
|
||||
Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), operand, _) => {
|
||||
check_operand(tcx, operand, span, body)
|
||||
},
|
||||
Rvalue::Cast(
|
||||
CastKind::Pointer(
|
||||
PointerCast::UnsafeFnPointer
|
||||
| PointerCast::ClosureFnPointer(_)
|
||||
| PointerCast::ReifyFnPointer,
|
||||
PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer,
|
||||
),
|
||||
_,
|
||||
_,
|
||||
|
@ -178,10 +159,7 @@ fn check_rvalue(
|
|||
deref_ty.ty
|
||||
} else {
|
||||
// We cannot allow this for now.
|
||||
return Err((
|
||||
span,
|
||||
"unsizing casts are only allowed for references right now".into(),
|
||||
));
|
||||
return Err((span, "unsizing casts are only allowed for references right now".into()));
|
||||
};
|
||||
let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id));
|
||||
if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
|
||||
|
@ -192,7 +170,7 @@ fn check_rvalue(
|
|||
// We just can't allow trait objects until we have figured out trait method calls.
|
||||
Err((span, "unsizing casts are not allowed in const fn".into()))
|
||||
}
|
||||
}
|
||||
},
|
||||
// binops are fine on integers
|
||||
Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
|
||||
check_operand(tcx, lhs, span, body)?;
|
||||
|
@ -201,13 +179,14 @@ fn check_rvalue(
|
|||
if ty.is_integral() || ty.is_bool() || ty.is_char() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err((span, "only int, `bool` and `char` operations are stable in const fn".into()))
|
||||
Err((
|
||||
span,
|
||||
"only int, `bool` and `char` operations are stable in const fn".into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
},
|
||||
Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()),
|
||||
Rvalue::NullaryOp(NullOp::Box, _) => {
|
||||
Err((span, "heap allocations are not allowed in const fn".into()))
|
||||
}
|
||||
Rvalue::NullaryOp(NullOp::Box, _) => Err((span, "heap allocations are not allowed in const fn".into())),
|
||||
Rvalue::UnaryOp(_, operand) => {
|
||||
let ty = operand.ty(body, tcx);
|
||||
if ty.is_integral() || ty.is_bool() {
|
||||
|
@ -215,39 +194,29 @@ fn check_rvalue(
|
|||
} else {
|
||||
Err((span, "only int and `bool` operations are stable in const fn".into()))
|
||||
}
|
||||
}
|
||||
},
|
||||
Rvalue::Aggregate(_, operands) => {
|
||||
for operand in operands {
|
||||
check_operand(tcx, operand, span, body)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn check_statement(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
def_id: DefId,
|
||||
statement: &Statement<'tcx>,
|
||||
) -> McfResult {
|
||||
fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statement: &Statement<'tcx>) -> McfResult {
|
||||
let span = statement.source_info.span;
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(box (place, rval)) => {
|
||||
check_place(tcx, *place, span, body)?;
|
||||
check_place(tcx, *place, span, body)?;
|
||||
check_rvalue(tcx, body, def_id, rval, span)
|
||||
}
|
||||
|
||||
StatementKind::FakeRead(_, place) => check_place(tcx, **place, span, body),
|
||||
},
|
||||
|
||||
StatementKind::FakeRead(_, place) |
|
||||
// just an assignment
|
||||
StatementKind::SetDiscriminant { place, .. } => {
|
||||
check_place(tcx, **place, span, body)
|
||||
}
|
||||
StatementKind::SetDiscriminant { place, .. } => check_place(tcx, **place, span, body),
|
||||
|
||||
StatementKind::LlvmInlineAsm { .. } => {
|
||||
Err((span, "cannot use inline assembly in const fn".into()))
|
||||
}
|
||||
StatementKind::LlvmInlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
|
||||
|
||||
// These are all NOPs
|
||||
StatementKind::StorageLive(_)
|
||||
|
@ -259,12 +228,7 @@ fn check_statement(
|
|||
}
|
||||
}
|
||||
|
||||
fn check_operand(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
operand: &Operand<'tcx>,
|
||||
span: Span,
|
||||
body: &Body<'tcx>,
|
||||
) -> McfResult {
|
||||
fn check_operand(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
|
||||
match operand {
|
||||
Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body),
|
||||
Operand::Constant(c) => match c.check_static_ptr(tcx) {
|
||||
|
@ -274,14 +238,9 @@ fn check_operand(
|
|||
}
|
||||
}
|
||||
|
||||
fn check_place(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
span: Span,
|
||||
body: &Body<'tcx>,
|
||||
) -> McfResult {
|
||||
fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
|
||||
let mut cursor = place.projection.as_ref();
|
||||
while let &[ref proj_base @ .., elem] = cursor {
|
||||
while let [ref proj_base @ .., elem] = *cursor {
|
||||
cursor = proj_base;
|
||||
match elem {
|
||||
ProjectionElem::Field(..) => {
|
||||
|
@ -289,26 +248,22 @@ fn check_place(
|
|||
if let Some(def) = base_ty.ty_adt_def() {
|
||||
// No union field accesses in `const fn`
|
||||
if def.is_union() {
|
||||
return Err((span, "accessing union fields is unstable".into()));
|
||||
return Err((span, "accessing union fields is unstable".into()));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
ProjectionElem::ConstantIndex { .. }
|
||||
| ProjectionElem::Downcast(..)
|
||||
| ProjectionElem::Subslice { .. }
|
||||
| ProjectionElem::Deref
|
||||
| ProjectionElem::Index(_) => {}
|
||||
| ProjectionElem::Index(_) => {},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_terminator(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &'a Body<'tcx>,
|
||||
terminator: &Terminator<'tcx>,
|
||||
) -> McfResult {
|
||||
fn check_terminator(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Terminator<'tcx>) -> McfResult {
|
||||
let span = terminator.source_info.span;
|
||||
match &terminator.kind {
|
||||
TerminatorKind::FalseEdge { .. }
|
||||
|
@ -318,20 +273,23 @@ fn check_terminator(
|
|||
| TerminatorKind::Resume
|
||||
| TerminatorKind::Unreachable => Ok(()),
|
||||
|
||||
TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body),
|
||||
TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body),
|
||||
TerminatorKind::DropAndReplace { place, value, .. } => {
|
||||
check_place(tcx, *place, span, body)?;
|
||||
check_place(tcx, *place, span, body)?;
|
||||
check_operand(tcx, value, span, body)
|
||||
}
|
||||
},
|
||||
|
||||
TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => {
|
||||
check_operand(tcx, discr, span, body)
|
||||
}
|
||||
TerminatorKind::SwitchInt {
|
||||
discr,
|
||||
switch_ty: _,
|
||||
values: _,
|
||||
targets: _,
|
||||
} => check_operand(tcx, discr, span, body),
|
||||
|
||||
TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())),
|
||||
TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
|
||||
Err((span, "const fn generators are unstable".into()))
|
||||
}
|
||||
},
|
||||
|
||||
TerminatorKind::Call {
|
||||
func,
|
||||
|
@ -343,8 +301,7 @@ fn check_terminator(
|
|||
} => {
|
||||
let fn_ty = func.ty(body, tcx);
|
||||
if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() {
|
||||
if !rustc_mir::const_eval::is_min_const_fn(tcx, fn_def_id)
|
||||
{
|
||||
if !rustc_mir::const_eval::is_min_const_fn(tcx, fn_def_id) {
|
||||
return Err((
|
||||
span,
|
||||
format!(
|
||||
|
@ -360,9 +317,7 @@ fn check_terminator(
|
|||
// within const fns. `transmute` is allowed in all other const contexts.
|
||||
// This won't really scale to more intrinsics or functions. Let's allow const
|
||||
// transmutes in const fn before we add more hacks to this.
|
||||
if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic
|
||||
&& tcx.item_name(fn_def_id) == sym::transmute
|
||||
{
|
||||
if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic && tcx.item_name(fn_def_id) == sym::transmute {
|
||||
return Err((
|
||||
span,
|
||||
"can only call `transmute` from const items, not `const fn`".into(),
|
||||
|
@ -378,14 +333,16 @@ fn check_terminator(
|
|||
} else {
|
||||
Err((span, "can only call other const fns within const fn".into()))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => {
|
||||
check_operand(tcx, cond, span, body)
|
||||
}
|
||||
TerminatorKind::Assert {
|
||||
cond,
|
||||
expected: _,
|
||||
msg: _,
|
||||
target: _,
|
||||
cleanup: _,
|
||||
} => check_operand(tcx, cond, span, body),
|
||||
|
||||
TerminatorKind::InlineAsm { .. } => {
|
||||
Err((span, "cannot use inline assembly in const fn".into()))
|
||||
}
|
||||
TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -235,8 +235,19 @@ impl EarlyLintPass for Write {
|
|||
}
|
||||
|
||||
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
|
||||
fn is_build_script(cx: &EarlyContext<'_>) -> bool {
|
||||
// Cargo sets the crate name for build scripts to `build_script_build`
|
||||
cx.sess
|
||||
.opts
|
||||
.crate_name
|
||||
.as_ref()
|
||||
.map_or(false, |crate_name| crate_name == "build_script_build")
|
||||
}
|
||||
|
||||
if mac.path == sym!(println) {
|
||||
span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
|
||||
if !is_build_script(cx) {
|
||||
span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
|
||||
}
|
||||
if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
|
||||
if fmt_str.symbol == Symbol::intern("") {
|
||||
span_lint_and_sugg(
|
||||
|
@ -251,7 +262,9 @@ impl EarlyLintPass for Write {
|
|||
}
|
||||
}
|
||||
} else if mac.path == sym!(print) {
|
||||
span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
|
||||
if !is_build_script(cx) {
|
||||
span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
|
||||
}
|
||||
if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
|
||||
if check_newlines(&fmt_str) {
|
||||
span_lint_and_then(
|
||||
|
|
7
clippy_workspace_tests/build.rs
Normal file
7
clippy_workspace_tests/build.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
#![deny(clippy::print_stdout)]
|
||||
|
||||
fn main() {
|
||||
// Test for #6041
|
||||
println!("Hello");
|
||||
print!("Hello");
|
||||
}
|
|
@ -189,7 +189,8 @@ declare_clippy_lint! {
|
|||
|
||||
* The section of lines prefixed with `///` constitutes the lint documentation
|
||||
section. This is the default documentation style and will be displayed
|
||||
[like this][example_lint_page].
|
||||
[like this][example_lint_page]. To render and open this documentation locally
|
||||
in a browser, run `cargo dev serve`.
|
||||
* `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the
|
||||
[lint naming guidelines][lint_naming] here when naming your lint.
|
||||
In short, the name should state the thing that is being checked for and
|
||||
|
|
|
@ -13,6 +13,7 @@ Lints] or [Common Tools].
|
|||
- [Setup](#setup)
|
||||
- [Building and Testing](#building-and-testing)
|
||||
- [`cargo dev`](#cargo-dev)
|
||||
- [PR](#pr)
|
||||
|
||||
## Get the Code
|
||||
|
||||
|
@ -110,3 +111,8 @@ cargo dev new_lint
|
|||
# (experimental) Setup Clippy to work with rust-analyzer
|
||||
cargo dev ra-setup
|
||||
```
|
||||
|
||||
## PR
|
||||
|
||||
We follow a rustc no merge-commit policy.
|
||||
See <https://rustc-dev-guide.rust-lang.org/contributing.html#opening-a-pr>.
|
||||
|
|
|
@ -110,7 +110,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
|
|||
},
|
||||
Lint {
|
||||
name: "borrow_interior_mutable_const",
|
||||
group: "correctness",
|
||||
group: "style",
|
||||
desc: "referencing `const` with interior mutability",
|
||||
deprecation: None,
|
||||
module: "non_copy_const",
|
||||
|
@ -334,7 +334,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
|
|||
},
|
||||
Lint {
|
||||
name: "declare_interior_mutable_const",
|
||||
group: "correctness",
|
||||
group: "style",
|
||||
desc: "declaring `const` with interior mutability",
|
||||
deprecation: None,
|
||||
module: "non_copy_const",
|
||||
|
@ -381,6 +381,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
|
|||
deprecation: None,
|
||||
module: "derive",
|
||||
},
|
||||
Lint {
|
||||
name: "disallowed_method",
|
||||
group: "nursery",
|
||||
desc: "use of a disallowed method call",
|
||||
deprecation: None,
|
||||
module: "disallowed_method",
|
||||
},
|
||||
Lint {
|
||||
name: "diverging_sub_expression",
|
||||
group: "complexity",
|
||||
|
@ -885,6 +892,20 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
|
|||
deprecation: None,
|
||||
module: "attrs",
|
||||
},
|
||||
Lint {
|
||||
name: "inline_asm_x86_att_syntax",
|
||||
group: "restriction",
|
||||
desc: "prefer Intel x86 assembly syntax",
|
||||
deprecation: None,
|
||||
module: "asm_syntax",
|
||||
},
|
||||
Lint {
|
||||
name: "inline_asm_x86_intel_syntax",
|
||||
group: "restriction",
|
||||
desc: "prefer AT&T x86 assembly syntax",
|
||||
deprecation: None,
|
||||
module: "asm_syntax",
|
||||
},
|
||||
Lint {
|
||||
name: "inline_fn_without_body",
|
||||
group: "correctness",
|
||||
|
@ -941,6 +962,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
|
|||
deprecation: None,
|
||||
module: "types",
|
||||
},
|
||||
Lint {
|
||||
name: "invisible_characters",
|
||||
group: "correctness",
|
||||
desc: "using an invisible character in a string literal, which is confusing",
|
||||
deprecation: None,
|
||||
module: "unicode",
|
||||
},
|
||||
Lint {
|
||||
name: "items_after_statements",
|
||||
group: "pedantic",
|
||||
|
@ -1860,7 +1888,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
|
|||
},
|
||||
Lint {
|
||||
name: "rc_buffer",
|
||||
group: "perf",
|
||||
group: "restriction",
|
||||
desc: "shared ownership of a buffer type",
|
||||
deprecation: None,
|
||||
module: "types",
|
||||
|
@ -2133,7 +2161,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
|
|||
},
|
||||
Lint {
|
||||
name: "string_lit_as_bytes",
|
||||
group: "style",
|
||||
group: "nursery",
|
||||
desc: "calling `as_bytes` on a string literal instead of using a byte string literal",
|
||||
deprecation: None,
|
||||
module: "strings",
|
||||
|
@ -2782,13 +2810,6 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
|
|||
deprecation: None,
|
||||
module: "misc",
|
||||
},
|
||||
Lint {
|
||||
name: "zero_width_space",
|
||||
group: "correctness",
|
||||
desc: "using a zero-width space in a string literal, which is confusing",
|
||||
deprecation: None,
|
||||
module: "unicode",
|
||||
},
|
||||
Lint {
|
||||
name: "zst_offset",
|
||||
group: "correctness",
|
||||
|
|
|
@ -1,27 +1,24 @@
|
|||
use lazy_static::lazy_static;
|
||||
use std::env;
|
||||
use std::lazy::SyncLazy;
|
||||
use std::path::PathBuf;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref CARGO_TARGET_DIR: PathBuf = {
|
||||
match env::var_os("CARGO_TARGET_DIR") {
|
||||
Some(v) => v.into(),
|
||||
None => env::current_dir().unwrap().join("target"),
|
||||
pub static CARGO_TARGET_DIR: SyncLazy<PathBuf> = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") {
|
||||
Some(v) => v.into(),
|
||||
None => env::current_dir().unwrap().join("target"),
|
||||
});
|
||||
|
||||
pub static TARGET_LIB: SyncLazy<PathBuf> = SyncLazy::new(|| {
|
||||
if let Some(path) = option_env!("TARGET_LIBS") {
|
||||
path.into()
|
||||
} else {
|
||||
let mut dir = CARGO_TARGET_DIR.clone();
|
||||
if let Some(target) = env::var_os("CARGO_BUILD_TARGET") {
|
||||
dir.push(target);
|
||||
}
|
||||
};
|
||||
pub static ref TARGET_LIB: PathBuf = {
|
||||
if let Some(path) = option_env!("TARGET_LIBS") {
|
||||
path.into()
|
||||
} else {
|
||||
let mut dir = CARGO_TARGET_DIR.clone();
|
||||
if let Some(target) = env::var_os("CARGO_BUILD_TARGET") {
|
||||
dir.push(target);
|
||||
}
|
||||
dir.push(env!("PROFILE"));
|
||||
dir
|
||||
}
|
||||
};
|
||||
}
|
||||
dir.push(env!("PROFILE"));
|
||||
dir
|
||||
}
|
||||
});
|
||||
|
||||
#[must_use]
|
||||
pub fn is_rustc_test_suite() -> bool {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#![feature(test)] // compiletest_rs requires this attribute
|
||||
#![feature(once_cell)]
|
||||
|
||||
use compiletest_rs as compiletest;
|
||||
use compiletest_rs::common::Mode as TestMode;
|
||||
|
@ -71,7 +72,7 @@ fn default_config() -> compiletest::Config {
|
|||
}
|
||||
|
||||
config.target_rustcflags = Some(format!(
|
||||
"-L {0} -L {1} -Dwarnings -Zui-testing {2}",
|
||||
"--emit=metadata -L {0} -L {1} -Dwarnings -Zui-testing {2}",
|
||||
host_lib().join("deps").display(),
|
||||
cargo::TARGET_LIB.join("deps").display(),
|
||||
third_party_crates(),
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
// Dogfood cannot run on Windows
|
||||
#![cfg(not(windows))]
|
||||
#![feature(once_cell)]
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use std::lazy::SyncLazy;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
mod cargo;
|
||||
|
||||
lazy_static! {
|
||||
static ref CLIPPY_PATH: PathBuf = cargo::TARGET_LIB.join("cargo-clippy");
|
||||
}
|
||||
static CLIPPY_PATH: SyncLazy<PathBuf> = SyncLazy::new(|| cargo::TARGET_LIB.join("cargo-clippy"));
|
||||
|
||||
#[test]
|
||||
fn dogfood_clippy() {
|
||||
|
|
1
tests/ui-toml/toml_disallowed_method/clippy.toml
Normal file
1
tests/ui-toml/toml_disallowed_method/clippy.toml
Normal file
|
@ -0,0 +1 @@
|
|||
disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match"]
|
|
@ -0,0 +1,13 @@
|
|||
#![warn(clippy::disallowed_method)]
|
||||
|
||||
extern crate regex;
|
||||
use regex::Regex;
|
||||
|
||||
fn main() {
|
||||
let a = vec![1, 2, 3, 4];
|
||||
let re = Regex::new(r"ab.*c").unwrap();
|
||||
|
||||
re.is_match("abc");
|
||||
|
||||
a.iter().sum::<i32>();
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
error: use of a disallowed method `regex::re_unicode::Regex::is_match`
|
||||
--> $DIR/conf_disallowed_method.rs:10:5
|
||||
|
|
||||
LL | re.is_match("abc");
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::disallowed-method` implied by `-D warnings`
|
||||
|
||||
error: use of a disallowed method `core::iter::traits::iterator::Iterator::sum`
|
||||
--> $DIR/conf_disallowed_method.rs:12:5
|
||||
|
|
||||
LL | a.iter().sum::<i32>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `third-party` at line 5 column 1
|
||||
error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `third-party` at line 5 column 1
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
31
tests/ui/asm_syntax.rs
Normal file
31
tests/ui/asm_syntax.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
#![feature(asm)]
|
||||
// only-x86_64
|
||||
|
||||
#[warn(clippy::inline_asm_x86_intel_syntax)]
|
||||
mod warn_intel {
|
||||
pub(super) unsafe fn use_asm() {
|
||||
asm!("");
|
||||
asm!("", options());
|
||||
asm!("", options(nostack));
|
||||
asm!("", options(att_syntax));
|
||||
asm!("", options(nostack, att_syntax));
|
||||
}
|
||||
}
|
||||
|
||||
#[warn(clippy::inline_asm_x86_att_syntax)]
|
||||
mod warn_att {
|
||||
pub(super) unsafe fn use_asm() {
|
||||
asm!("");
|
||||
asm!("", options());
|
||||
asm!("", options(nostack));
|
||||
asm!("", options(att_syntax));
|
||||
asm!("", options(nostack, att_syntax));
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
warn_att::use_asm();
|
||||
warn_intel::use_asm();
|
||||
}
|
||||
}
|
44
tests/ui/asm_syntax.stderr
Normal file
44
tests/ui/asm_syntax.stderr
Normal file
|
@ -0,0 +1,44 @@
|
|||
error: Intel x86 assembly syntax used
|
||||
--> $DIR/asm_syntax.rs:7:9
|
||||
|
|
||||
LL | asm!("");
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings`
|
||||
= help: use AT&T x86 assembly syntax
|
||||
|
||||
error: Intel x86 assembly syntax used
|
||||
--> $DIR/asm_syntax.rs:8:9
|
||||
|
|
||||
LL | asm!("", options());
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use AT&T x86 assembly syntax
|
||||
|
||||
error: Intel x86 assembly syntax used
|
||||
--> $DIR/asm_syntax.rs:9:9
|
||||
|
|
||||
LL | asm!("", options(nostack));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use AT&T x86 assembly syntax
|
||||
|
||||
error: AT&T x86 assembly syntax used
|
||||
--> $DIR/asm_syntax.rs:21:9
|
||||
|
|
||||
LL | asm!("", options(att_syntax));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings`
|
||||
= help: use Intel x86 assembly syntax
|
||||
|
||||
error: AT&T x86 assembly syntax used
|
||||
--> $DIR/asm_syntax.rs:22:9
|
||||
|
|
||||
LL | asm!("", options(nostack, att_syntax));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use Intel x86 assembly syntax
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
|
@ -1,8 +1,5 @@
|
|||
#![warn(clippy::inline_always, clippy::deprecated_semver)]
|
||||
#![allow(clippy::assertions_on_constants)]
|
||||
// Test that the whole restriction group is not enabled
|
||||
#![warn(clippy::restriction)]
|
||||
#![deny(clippy::restriction)]
|
||||
#![allow(clippy::missing_docs_in_private_items, clippy::panic, clippy::unreachable)]
|
||||
|
||||
#[inline(always)]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea
|
||||
--> $DIR/attrs.rs:8:1
|
||||
--> $DIR/attrs.rs:5:1
|
||||
|
|
||||
LL | #[inline(always)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
@ -7,7 +7,7 @@ LL | #[inline(always)]
|
|||
= note: `-D clippy::inline-always` implied by `-D warnings`
|
||||
|
||||
error: the since field must contain a semver-compliant version
|
||||
--> $DIR/attrs.rs:28:14
|
||||
--> $DIR/attrs.rs:25:14
|
||||
|
|
||||
LL | #[deprecated(since = "forever")]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
@ -15,27 +15,10 @@ LL | #[deprecated(since = "forever")]
|
|||
= note: `-D clippy::deprecated-semver` implied by `-D warnings`
|
||||
|
||||
error: the since field must contain a semver-compliant version
|
||||
--> $DIR/attrs.rs:31:14
|
||||
--> $DIR/attrs.rs:28:14
|
||||
|
|
||||
LL | #[deprecated(since = "1")]
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: restriction lints are not meant to be all enabled
|
||||
--> $DIR/attrs.rs:4:9
|
||||
|
|
||||
LL | #![warn(clippy::restriction)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
|
||||
= help: try enabling only the lints you really need
|
||||
|
||||
error: restriction lints are not meant to be all enabled
|
||||
--> $DIR/attrs.rs:5:9
|
||||
|
|
||||
LL | #![deny(clippy::restriction)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try enabling only the lints you really need
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
// compile-flags: --emit=link
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
#![feature(repr128, proc_macro_hygiene, proc_macro_quote)]
|
||||
#![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)]
|
||||
#![allow(clippy::useless_conversion)]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
@ -11,7 +12,11 @@ extern crate syn;
|
|||
use proc_macro::TokenStream;
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::parse_macro_input;
|
||||
use syn::{parse_quote, ItemTrait, TraitItem};
|
||||
use syn::spanned::Spanned;
|
||||
use syn::token::Star;
|
||||
use syn::{
|
||||
parse_quote, FnArg, ImplItem, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, TraitItem, Type,
|
||||
};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
|
@ -35,3 +40,56 @@ pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream {
|
|||
}
|
||||
TokenStream::from(quote!(#item))
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
fn make_name(count: usize) -> String {
|
||||
format!("'life{}", count)
|
||||
}
|
||||
|
||||
fn mut_receiver_of(sig: &mut Signature) -> Option<&mut FnArg> {
|
||||
let arg = sig.inputs.first_mut()?;
|
||||
if let FnArg::Typed(PatType { pat, .. }) = arg {
|
||||
if let Pat::Ident(PatIdent { ident, .. }) = &**pat {
|
||||
if ident == "self" {
|
||||
return Some(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
let mut elided = 0;
|
||||
let mut item = parse_macro_input!(input as ItemImpl);
|
||||
|
||||
// Look for methods having arbitrary self type taken by &mut ref
|
||||
for inner in &mut item.items {
|
||||
if let ImplItem::Method(method) = inner {
|
||||
if let Some(FnArg::Typed(pat_type)) = mut_receiver_of(&mut method.sig) {
|
||||
if let box Type::Reference(reference) = &mut pat_type.ty {
|
||||
// Target only unnamed lifetimes
|
||||
let name = match &reference.lifetime {
|
||||
Some(lt) if lt.ident == "_" => make_name(elided),
|
||||
None => make_name(elided),
|
||||
_ => continue,
|
||||
};
|
||||
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.
|
||||
// A default span is needed to mark the code as coming from expansion.
|
||||
let span = Star::default().span();
|
||||
|
||||
// Replace old lifetime with the named one
|
||||
let lifetime = Lifetime::new(&name, span);
|
||||
reference.lifetime = Some(parse_quote!(#lifetime));
|
||||
|
||||
// Add lifetime to the generics of the method
|
||||
method.sig.generics.params.push(parse_quote!(#lifetime));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TokenStream::from(quote!(#item))
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// compile-flags: --emit=link
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
|
8
tests/ui/blanket_clippy_restriction_lints.rs
Normal file
8
tests/ui/blanket_clippy_restriction_lints.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
#![warn(clippy::blanket_clippy_restriction_lints)]
|
||||
|
||||
//! Test that the whole restriction group is not enabled
|
||||
#![warn(clippy::restriction)]
|
||||
#![deny(clippy::restriction)]
|
||||
#![forbid(clippy::restriction)]
|
||||
|
||||
fn main() {}
|
27
tests/ui/blanket_clippy_restriction_lints.stderr
Normal file
27
tests/ui/blanket_clippy_restriction_lints.stderr
Normal file
|
@ -0,0 +1,27 @@
|
|||
error: restriction lints are not meant to be all enabled
|
||||
--> $DIR/blanket_clippy_restriction_lints.rs:4:9
|
||||
|
|
||||
LL | #![warn(clippy::restriction)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
|
||||
= help: try enabling only the lints you really need
|
||||
|
||||
error: restriction lints are not meant to be all enabled
|
||||
--> $DIR/blanket_clippy_restriction_lints.rs:5:9
|
||||
|
|
||||
LL | #![deny(clippy::restriction)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try enabling only the lints you really need
|
||||
|
||||
error: restriction lints are not meant to be all enabled
|
||||
--> $DIR/blanket_clippy_restriction_lints.rs:6:11
|
||||
|
|
||||
LL | #![forbid(clippy::restriction)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try enabling only the lints you really need
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/1698
|
||||
|
||||
pub trait Trait {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// compile-flags: --emit=link
|
||||
// no-prefer-dynamic
|
||||
// ^ compiletest by default builds all aux files as dylibs, but we don't want that for proc-macro
|
||||
// crates. If we don't set this, compiletest will override the `crate_type` attribute below and
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/478
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![deny(clippy::all)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(clippy::all)]
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/1588
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
/// Should not trigger an ICE in `SpanlessEq` / `consts::constant`
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(clippy::all)]
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/1969
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)]
|
||||
|
||||
/// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
/// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/2727
|
||||
|
||||
pub fn f(new: fn()) {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(
|
||||
unused_variables,
|
||||
clippy::blacklisted_name,
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
// See rust-lang/rust-clippy#2774.
|
||||
|
|
10
tests/ui/crashes/ice-2774.stderr
Normal file
10
tests/ui/crashes/ice-2774.stderr
Normal file
|
@ -0,0 +1,10 @@
|
|||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/ice-2774.rs:15:1
|
||||
|
|
||||
LL | pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::needless-lifetimes` implied by `-D warnings`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/2862
|
||||
|
||||
pub trait FooMap {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/2865
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/2865
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![warn(clippy::all)]
|
||||
#![allow(clippy::blacklisted_name)]
|
||||
#![allow(unused)]
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// aux-build:proc_macro_crash.rs
|
||||
// run-pass
|
||||
|
||||
#![warn(clippy::suspicious_else_formatting)]
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/3747
|
||||
|
||||
macro_rules! a {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![warn(clippy::use_self)]
|
||||
|
||||
#[path = "auxiliary/ice-4727-aux.rs"]
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// run-pass
|
||||
const COUNT: usize = 2;
|
||||
struct Thing;
|
||||
trait Dummy {}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![deny(clippy::all)]
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/700
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![deny(clippy::all)]
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/1336
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(clippy::comparison_chain)]
|
||||
#![deny(clippy::if_same_then_else)]
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/825
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
/// Issue: https://github.com/rust-lang/rust-clippy/issues/2596
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![deny(clippy::match_same_arms)]
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/2427
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![deny(clippy::mut_mut, clippy::zero_ptr, clippy::cmp_nan)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#[deny(clippy::all)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![deny(clippy::needless_lifetimes)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
|
|
14
tests/ui/crashes/needless_lifetimes_impl_trait.stderr
Normal file
14
tests/ui/crashes/needless_lifetimes_impl_trait.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes_impl_trait.rs:15:5
|
||||
|
|
||||
LL | fn baz<'a>(&'a self) -> impl Foo + 'a {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/needless_lifetimes_impl_trait.rs:1:9
|
||||
|
|
||||
LL | #![deny(clippy::needless_lifetimes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#[macro_use]
|
||||
extern crate clippy_mini_macro_test;
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(clippy::blacklisted_name)]
|
||||
|
||||
pub fn foo(bar: *const u8) {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
/// Test for https://github.com/rust-lang/rust-clippy/issues/1346
|
||||
|
||||
#[deny(warnings)]
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![warn(clippy::single_match_else)]
|
||||
|
||||
//! Test for https://github.com/rust-lang/rust-clippy/issues/1588
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![feature(trivial_bounds)]
|
||||
#![allow(unused, trivial_bounds)]
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// run-pass
|
||||
|
||||
#![allow(clippy::useless_attribute)] //issue #2910
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
@ -174,3 +174,11 @@ mod issue_3739 {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Issue #5542
|
||||
///
|
||||
/// This shouldn't warn for `boxed_local` as it is intended to called from non-Rust code.
|
||||
pub extern "C" fn do_not_warn_me(_c_pointer: Box<String>) -> () {}
|
||||
|
||||
#[rustfmt::skip] // Forces rustfmt to not add ABI
|
||||
pub extern fn do_not_warn_me_no_abi(_c_pointer: Box<String>) -> () {}
|
||||
|
|
|
@ -38,54 +38,54 @@ mod issue_1219 {
|
|||
let text = "banana";
|
||||
let mut count = 0;
|
||||
for ch in text.chars() {
|
||||
println!("{}", count);
|
||||
if ch == 'a' {
|
||||
continue;
|
||||
}
|
||||
count += 1;
|
||||
println!("{}", count);
|
||||
}
|
||||
|
||||
// should not trigger the lint because the count is conditional
|
||||
let text = "banana";
|
||||
let mut count = 0;
|
||||
for ch in text.chars() {
|
||||
println!("{}", count);
|
||||
if ch == 'a' {
|
||||
count += 1;
|
||||
}
|
||||
println!("{}", count);
|
||||
}
|
||||
|
||||
// should trigger the lint because the count is not conditional
|
||||
let text = "banana";
|
||||
let mut count = 0;
|
||||
for ch in text.chars() {
|
||||
println!("{}", count);
|
||||
count += 1;
|
||||
if ch == 'a' {
|
||||
continue;
|
||||
}
|
||||
println!("{}", count);
|
||||
}
|
||||
|
||||
// should trigger the lint because the count is not conditional
|
||||
let text = "banana";
|
||||
let mut count = 0;
|
||||
for ch in text.chars() {
|
||||
println!("{}", count);
|
||||
count += 1;
|
||||
for i in 0..2 {
|
||||
let _ = 123;
|
||||
}
|
||||
println!("{}", count);
|
||||
}
|
||||
|
||||
// should not trigger the lint because the count is incremented multiple times
|
||||
let text = "banana";
|
||||
let mut count = 0;
|
||||
for ch in text.chars() {
|
||||
println!("{}", count);
|
||||
count += 1;
|
||||
for i in 0..2 {
|
||||
count += 1;
|
||||
}
|
||||
println!("{}", count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,30 +96,30 @@ mod issue_3308 {
|
|||
let mut skips = 0;
|
||||
let erasures = vec![];
|
||||
for i in 0..10 {
|
||||
println!("{}", skips);
|
||||
while erasures.contains(&(i + skips)) {
|
||||
skips += 1;
|
||||
}
|
||||
println!("{}", skips);
|
||||
}
|
||||
|
||||
// should not trigger the lint because the count is incremented multiple times
|
||||
let mut skips = 0;
|
||||
for i in 0..10 {
|
||||
println!("{}", skips);
|
||||
let mut j = 0;
|
||||
while j < 5 {
|
||||
skips += 1;
|
||||
j += 1;
|
||||
}
|
||||
println!("{}", skips);
|
||||
}
|
||||
|
||||
// should not trigger the lint because the count is incremented multiple times
|
||||
let mut skips = 0;
|
||||
for i in 0..10 {
|
||||
println!("{}", skips);
|
||||
for j in 0..5 {
|
||||
skips += 1;
|
||||
}
|
||||
println!("{}", skips);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -145,3 +145,16 @@ mod issue_4732 {
|
|||
let _closure = || println!("index: {}", index);
|
||||
}
|
||||
}
|
||||
|
||||
mod issue_4677 {
|
||||
pub fn test() {
|
||||
let slice = &[1, 2, 3];
|
||||
|
||||
// should not trigger the lint because the count is used after incremented
|
||||
let mut count = 0;
|
||||
for _i in slice {
|
||||
count += 1;
|
||||
println!("{}", count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,4 +40,8 @@ fn main() {
|
|||
// Ignore literals in macros
|
||||
let _ = mac1!();
|
||||
let _ = mac2!();
|
||||
|
||||
// Issue #6096
|
||||
// Allow separating exponent with '_'
|
||||
let _ = 1.025_011_10_E0;
|
||||
}
|
||||
|
|
|
@ -40,4 +40,8 @@ fn main() {
|
|||
// Ignore literals in macros
|
||||
let _ = mac1!();
|
||||
let _ = mac2!();
|
||||
|
||||
// Issue #6096
|
||||
// Allow separating exponent with '_'
|
||||
let _ = 1.025_011_10_E0;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(dead_code, unused_variables, clippy::excessive_precision)]
|
||||
#![allow(
|
||||
dead_code,
|
||||
unused_variables,
|
||||
clippy::excessive_precision,
|
||||
clippy::inconsistent_digit_grouping
|
||||
)]
|
||||
|
||||
fn main() {
|
||||
let fail14 = 2_i32;
|
||||
|
@ -12,13 +17,13 @@ fn main() {
|
|||
let fail20 = 2_i8; //
|
||||
let fail21 = 4_i16; //
|
||||
|
||||
let fail24 = 12.34_f64;
|
||||
let ok24 = 12.34_64;
|
||||
let fail25 = 1E2_f32;
|
||||
let fail26 = 43E7_f64;
|
||||
let fail27 = 243E17_f32;
|
||||
#[allow(overflowing_literals)]
|
||||
let fail28 = 241_251_235E723_f64;
|
||||
let fail29 = 42_279.911_f32;
|
||||
let ok29 = 42279.911_32;
|
||||
|
||||
let _ = 1.123_45E1_f32;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(dead_code, unused_variables, clippy::excessive_precision)]
|
||||
#![allow(
|
||||
dead_code,
|
||||
unused_variables,
|
||||
clippy::excessive_precision,
|
||||
clippy::inconsistent_digit_grouping
|
||||
)]
|
||||
|
||||
fn main() {
|
||||
let fail14 = 2_32;
|
||||
|
@ -12,13 +17,13 @@ fn main() {
|
|||
let fail20 = 2__8; //
|
||||
let fail21 = 4___16; //
|
||||
|
||||
let fail24 = 12.34_64;
|
||||
let ok24 = 12.34_64;
|
||||
let fail25 = 1E2_32;
|
||||
let fail26 = 43E7_64;
|
||||
let fail27 = 243E17_32;
|
||||
#[allow(overflowing_literals)]
|
||||
let fail28 = 241251235E723_64;
|
||||
let fail29 = 42279.911_32;
|
||||
let ok29 = 42279.911_32;
|
||||
|
||||
let _ = 1.12345E1_32;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: mistyped literal suffix
|
||||
--> $DIR/mistyped_literal_suffix.rs:6:18
|
||||
--> $DIR/mistyped_literal_suffix.rs:11:18
|
||||
|
|
||||
LL | let fail14 = 2_32;
|
||||
| ^^^^ help: did you mean to write: `2_i32`
|
||||
|
@ -7,76 +7,64 @@ LL | let fail14 = 2_32;
|
|||
= note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/mistyped_literal_suffix.rs:7:18
|
||||
--> $DIR/mistyped_literal_suffix.rs:12:18
|
||||
|
|
||||
LL | let fail15 = 4_64;
|
||||
| ^^^^ help: did you mean to write: `4_i64`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/mistyped_literal_suffix.rs:8:18
|
||||
--> $DIR/mistyped_literal_suffix.rs:13:18
|
||||
|
|
||||
LL | let fail16 = 7_8; //
|
||||
| ^^^ help: did you mean to write: `7_i8`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/mistyped_literal_suffix.rs:9:18
|
||||
--> $DIR/mistyped_literal_suffix.rs:14:18
|
||||
|
|
||||
LL | let fail17 = 23_16; //
|
||||
| ^^^^^ help: did you mean to write: `23_i16`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/mistyped_literal_suffix.rs:12:18
|
||||
--> $DIR/mistyped_literal_suffix.rs:17:18
|
||||
|
|
||||
LL | let fail20 = 2__8; //
|
||||
| ^^^^ help: did you mean to write: `2_i8`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/mistyped_literal_suffix.rs:13:18
|
||||
--> $DIR/mistyped_literal_suffix.rs:18:18
|
||||
|
|
||||
LL | let fail21 = 4___16; //
|
||||
| ^^^^^^ help: did you mean to write: `4_i16`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/mistyped_literal_suffix.rs:15:18
|
||||
|
|
||||
LL | let fail24 = 12.34_64;
|
||||
| ^^^^^^^^ help: did you mean to write: `12.34_f64`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/mistyped_literal_suffix.rs:16:18
|
||||
--> $DIR/mistyped_literal_suffix.rs:21:18
|
||||
|
|
||||
LL | let fail25 = 1E2_32;
|
||||
| ^^^^^^ help: did you mean to write: `1E2_f32`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/mistyped_literal_suffix.rs:17:18
|
||||
--> $DIR/mistyped_literal_suffix.rs:22:18
|
||||
|
|
||||
LL | let fail26 = 43E7_64;
|
||||
| ^^^^^^^ help: did you mean to write: `43E7_f64`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/mistyped_literal_suffix.rs:18:18
|
||||
--> $DIR/mistyped_literal_suffix.rs:23:18
|
||||
|
|
||||
LL | let fail27 = 243E17_32;
|
||||
| ^^^^^^^^^ help: did you mean to write: `243E17_f32`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/mistyped_literal_suffix.rs:20:18
|
||||
--> $DIR/mistyped_literal_suffix.rs:25:18
|
||||
|
|
||||
LL | let fail28 = 241251235E723_64;
|
||||
| ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/mistyped_literal_suffix.rs:21:18
|
||||
|
|
||||
LL | let fail29 = 42279.911_32;
|
||||
| ^^^^^^^^^^^^ help: did you mean to write: `42_279.911_f32`
|
||||
|
||||
error: mistyped literal suffix
|
||||
--> $DIR/mistyped_literal_suffix.rs:23:13
|
||||
--> $DIR/mistyped_literal_suffix.rs:28:13
|
||||
|
|
||||
LL | let _ = 1.12345E1_32;
|
||||
| ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32`
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
|
|
45
tests/ui/needless_arbitrary_self_type_unfixable.rs
Normal file
45
tests/ui/needless_arbitrary_self_type_unfixable.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
// aux-build:proc_macro_attr.rs
|
||||
|
||||
#![warn(clippy::needless_arbitrary_self_type)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate proc_macro_attr;
|
||||
|
||||
mod issue_6089 {
|
||||
// Check that we don't lint if the `self` parameter comes from expansion
|
||||
|
||||
macro_rules! test_from_expansion {
|
||||
() => {
|
||||
trait T1 {
|
||||
fn test(self: &Self);
|
||||
}
|
||||
|
||||
struct S1 {}
|
||||
|
||||
impl T1 for S1 {
|
||||
fn test(self: &Self) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test_from_expansion!();
|
||||
|
||||
// If only the lifetime name comes from expansion we will lint, but the suggestion will have
|
||||
// placeholders and will not be applied automatically, as we can't reliably know the original name.
|
||||
// This specific case happened with async_trait.
|
||||
|
||||
trait T2 {
|
||||
fn call_with_mut_self(&mut self);
|
||||
}
|
||||
|
||||
struct S2 {}
|
||||
|
||||
// The method's signature will be expanded to:
|
||||
// fn call_with_mut_self<'life0>(self: &'life0 mut Self) {}
|
||||
#[rename_my_lifetimes]
|
||||
impl T2 for S2 {
|
||||
fn call_with_mut_self(self: &mut Self) {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
10
tests/ui/needless_arbitrary_self_type_unfixable.stderr
Normal file
10
tests/ui/needless_arbitrary_self_type_unfixable.stderr
Normal file
|
@ -0,0 +1,10 @@
|
|||
error: the type of the `self` parameter does not need to be arbitrary
|
||||
--> $DIR/needless_arbitrary_self_type_unfixable.rs:41:31
|
||||
|
|
||||
LL | fn call_with_mut_self(self: &mut Self) {}
|
||||
| ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'_ mut self`
|
||||
|
|
||||
= note: `-D clippy::needless-arbitrary-self-type` implied by `-D warnings`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -259,4 +259,102 @@ mod issue4291 {
|
|||
}
|
||||
}
|
||||
|
||||
mod issue2944 {
|
||||
trait Foo {}
|
||||
struct Bar {}
|
||||
struct Baz<'a> {
|
||||
bar: &'a Bar,
|
||||
}
|
||||
|
||||
impl<'a> Foo for Baz<'a> {}
|
||||
impl Bar {
|
||||
fn baz<'a>(&'a self) -> impl Foo + 'a {
|
||||
Baz { bar: self }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod nested_elision_sites {
|
||||
// issue #issue2944
|
||||
|
||||
// closure trait bounds subject to nested elision
|
||||
// don't lint because they refer to outer lifetimes
|
||||
fn trait_fn<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
|
||||
move || i
|
||||
}
|
||||
fn trait_fn_mut<'a>(i: &'a i32) -> impl FnMut() -> &'a i32 {
|
||||
move || i
|
||||
}
|
||||
fn trait_fn_once<'a>(i: &'a i32) -> impl FnOnce() -> &'a i32 {
|
||||
move || i
|
||||
}
|
||||
|
||||
// don't lint
|
||||
fn impl_trait_in_input_position<'a>(f: impl Fn() -> &'a i32) -> &'a i32 {
|
||||
f()
|
||||
}
|
||||
fn impl_trait_in_output_position<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
|
||||
move || i
|
||||
}
|
||||
// lint
|
||||
fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
|
||||
f(i)
|
||||
}
|
||||
fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
|
||||
f(i)
|
||||
}
|
||||
|
||||
// don't lint
|
||||
fn generics_not_elidable<'a, T: Fn() -> &'a i32>(f: T) -> &'a i32 {
|
||||
f()
|
||||
}
|
||||
// lint
|
||||
fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
|
||||
f(i)
|
||||
}
|
||||
|
||||
// don't lint
|
||||
fn where_clause_not_elidable<'a, T>(f: T) -> &'a i32
|
||||
where
|
||||
T: Fn() -> &'a i32,
|
||||
{
|
||||
f()
|
||||
}
|
||||
// lint
|
||||
fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
|
||||
where
|
||||
T: Fn(&i32) -> &i32,
|
||||
{
|
||||
f(i)
|
||||
}
|
||||
|
||||
// don't lint
|
||||
fn pointer_fn_in_input_position<'a>(f: fn(&'a i32) -> &'a i32, i: &'a i32) -> &'a i32 {
|
||||
f(i)
|
||||
}
|
||||
fn pointer_fn_in_output_position<'a>(_: &'a i32) -> fn(&'a i32) -> &'a i32 {
|
||||
|i| i
|
||||
}
|
||||
// lint
|
||||
fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
|
||||
f(i)
|
||||
}
|
||||
|
||||
// don't lint
|
||||
fn nested_fn_pointer_1<'a>(_: &'a i32) -> fn(fn(&'a i32) -> &'a i32) -> i32 {
|
||||
|f| 42
|
||||
}
|
||||
fn nested_fn_pointer_2<'a>(_: &'a i32) -> impl Fn(fn(&'a i32)) {
|
||||
|f| ()
|
||||
}
|
||||
|
||||
// lint
|
||||
fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
|
||||
|f| 42
|
||||
}
|
||||
fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
|
||||
|f| ()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -102,5 +102,53 @@ error: explicit lifetimes given in parameter types where they could be elided (o
|
|||
LL | fn needless_lt<'a>(_x: &'a u8) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:271:9
|
||||
|
|
||||
LL | fn baz<'a>(&'a self) -> impl Foo + 'a {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:300:5
|
||||
|
|
||||
LL | fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:303:5
|
||||
|
|
||||
LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:312:5
|
||||
|
|
||||
LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:324:5
|
||||
|
|
||||
LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:339:5
|
||||
|
|
||||
LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:352:5
|
||||
|
|
||||
LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
|
||||
--> $DIR/needless_lifetimes.rs:355:5
|
||||
|
|
||||
LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 25 previous errors
|
||||
|
||||
|
|
|
@ -82,6 +82,20 @@ fn main() {
|
|||
for i in 1..3 {
|
||||
println!("{}", arr[i]);
|
||||
}
|
||||
|
||||
// Fix #5945
|
||||
let mut vec = vec![1, 2, 3, 4];
|
||||
for i in 0..vec.len() - 1 {
|
||||
vec[i] += 1;
|
||||
}
|
||||
let mut vec = vec![1, 2, 3, 4];
|
||||
for i in vec.len() - 3..vec.len() {
|
||||
vec[i] += 1;
|
||||
}
|
||||
let mut vec = vec![1, 2, 3, 4];
|
||||
for i in vec.len() - 3..vec.len() - 1 {
|
||||
vec[i] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
mod issue2277 {
|
||||
|
|
|
@ -58,6 +58,12 @@ fn or_fun_call() {
|
|||
let without_default = Some(Foo);
|
||||
without_default.unwrap_or_else(Foo::new);
|
||||
|
||||
let mut map = HashMap::<u64, String>::new();
|
||||
map.entry(42).or_insert_with(String::new);
|
||||
|
||||
let mut btree = BTreeMap::<u64, String>::new();
|
||||
btree.entry(42).or_insert_with(String::new);
|
||||
|
||||
let stringy = Some(String::from(""));
|
||||
let _ = stringy.unwrap_or_else(|| "".to_owned());
|
||||
|
||||
|
@ -110,23 +116,4 @@ fn f() -> Option<()> {
|
|||
Some(())
|
||||
}
|
||||
|
||||
// Issue 5886 - const fn (with no arguments)
|
||||
pub fn skip_const_fn_with_no_args() {
|
||||
const fn foo() -> Option<i32> {
|
||||
Some(42)
|
||||
}
|
||||
let _ = None.or(foo());
|
||||
|
||||
// See issue #5693.
|
||||
let mut map = std::collections::HashMap::new();
|
||||
map.insert(1, vec![1]);
|
||||
map.entry(1).or_insert(vec![]);
|
||||
|
||||
let mut map = HashMap::<u64, String>::new();
|
||||
map.entry(42).or_insert(String::new());
|
||||
|
||||
let mut btree = BTreeMap::<u64, String>::new();
|
||||
btree.entry(42).or_insert(String::new());
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue