Merge remote-tracking branch 'upstream/master' into rustup

This commit is contained in:
Philipp Krones 2023-11-02 17:01:56 +01:00
commit 95dc7be92f
No known key found for this signature in database
GPG key ID: 1CA0DF2AF59D68A5
358 changed files with 3171 additions and 2172 deletions

View file

@ -83,9 +83,9 @@ pub fn span_lint_and_help<T: LintContext>(
cx.struct_span_lint(lint, span, msg.to_string(), |diag| {
let help = help.to_string();
if let Some(help_span) = help_span {
diag.span_help(help_span, help.to_string());
diag.span_help(help_span, help);
} else {
diag.help(help.to_string());
diag.help(help);
}
docs_link(diag, lint);
diag
@ -193,7 +193,7 @@ pub fn span_lint_hir_and_then(
/// |
/// = note: `-D fold-any` implied by `-D warnings`
/// ```
#[cfg_attr(feature = "internal", allow(clippy::collapsible_span_lint_calls))]
#[expect(clippy::collapsible_span_lint_calls)]
pub fn span_lint_and_sugg<T: LintContext>(
cx: &T,
lint: &'static Lint,

View file

@ -54,7 +54,6 @@ pub mod higher;
mod hir_utils;
pub mod macros;
pub mod mir;
pub mod msrvs;
pub mod numeric_literal;
pub mod paths;
pub mod ptr;
@ -144,7 +143,7 @@ macro_rules! extract_msrv_attr {
/// instead.
///
/// Examples:
/// ```
/// ```no_run
/// let abc = 1;
/// // ^ output
/// let def = abc;
@ -699,7 +698,7 @@ pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
///
/// Use this if you want to find the `TraitRef` of the `Add` trait in this example:
///
/// ```rust
/// ```no_run
/// struct Point(isize, isize);
///
/// impl std::ops::Add for Point {
@ -895,7 +894,7 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
///
/// For example, given the following function:
///
/// ```
/// ```no_run
/// fn f<'a>(iter: &mut impl Iterator<Item = (usize, &'a mut String)>) {
/// for item in iter {
/// let s = item.1;
@ -1609,7 +1608,7 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
/// Returns the pre-expansion span if the span directly comes from an expansion
/// of the macro `name`.
/// The difference with [`is_expn_of`] is that in
/// ```rust
/// ```no_run
/// # macro_rules! foo { ($name:tt!$args:tt) => { $name!$args } }
/// # macro_rules! bar { ($e:expr) => { $e } }
/// foo!(bar!(42));
@ -2032,17 +2031,26 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
/// * `|x| return x`
/// * `|x| { return x }`
/// * `|x| { return x; }`
/// * `|(x, y)| (x, y)`
///
/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
let id = if_chain! {
if let [param] = func.params;
if let PatKind::Binding(_, id, _, _) = param.pat.kind;
then {
id
} else {
return false;
fn check_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
match (pat.kind, expr.kind) {
(PatKind::Binding(_, id, _, _), _) => {
path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty()
},
(PatKind::Tuple(pats, dotdot), ExprKind::Tup(tup))
if dotdot.as_opt_usize().is_none() && pats.len() == tup.len() =>
{
pats.iter().zip(tup).all(|(pat, expr)| check_pat(cx, pat, expr))
},
_ => false,
}
}
let [param] = func.params else {
return false;
};
let mut expr = func.value;
@ -2075,7 +2083,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
}
}
},
_ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(),
_ => return check_pat(cx, param.pat, expr),
}
}
}
@ -2195,7 +2203,7 @@ pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
/// Check if parent of a hir node is a trait implementation block.
/// For example, `f` in
/// ```rust
/// ```no_run
/// # struct S;
/// # trait Trait { fn f(); }
/// impl Trait for S {
@ -2952,3 +2960,15 @@ op_utils! {
Shl ShlAssign
Shr ShrAssign
}
/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_`
/// that is not locally used.
pub fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: impl Visitable<'tcx>) -> bool {
match *pat {
PatKind::Wild => true,
PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => {
!visitors::is_local_used(cx, body, id)
},
_ => false,
}
}

View file

@ -1,130 +0,0 @@
use rustc_ast::Attribute;
use rustc_semver::RustcVersion;
use rustc_session::Session;
use serde::Deserialize;
use crate::attrs::get_unique_attr;
macro_rules! msrv_aliases {
($($major:literal,$minor:literal,$patch:literal {
$($name:ident),* $(,)?
})*) => {
$($(
pub const $name: RustcVersion = RustcVersion::new($major, $minor, $patch);
)*)*
};
}
// names may refer to stabilized feature flags or library items
msrv_aliases! {
1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN }
1,68,0 { PATH_MAIN_SEPARATOR_STR }
1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
1,55,0 { SEEK_REWIND }
1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST }
1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS }
1,50,0 { BOOL_THEN, CLAMP }
1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN }
1,46,0 { CONST_IF_MATCH }
1,45,0 { STR_STRIP_PREFIX }
1,43,0 { LOG2_10, LOG10_2 }
1,42,0 { MATCHES_MACRO, SLICE_PATTERNS, PTR_SLICE_RAW_PARTS }
1,41,0 { RE_REBALANCING_COHERENCE, RESULT_MAP_OR_ELSE }
1,40,0 { MEM_TAKE, NON_EXHAUSTIVE, OPTION_AS_DEREF }
1,38,0 { POINTER_CAST, REM_EUCLID }
1,37,0 { TYPE_ALIAS_ENUM_VARIANTS }
1,36,0 { ITERATOR_COPIED }
1,35,0 { OPTION_COPIED, RANGE_CONTAINS }
1,34,0 { TRY_FROM }
1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
1,28,0 { FROM_BOOL }
1,27,0 { ITERATOR_TRY_FOLD }
1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
1,24,0 { IS_ASCII_DIGIT }
1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN }
1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
1,16,0 { STR_REPEAT }
1,15,0 { MAYBE_BOUND_IN_WHERE }
}
/// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]`
#[derive(Debug, Clone)]
pub struct Msrv {
stack: Vec<RustcVersion>,
}
impl<'de> Deserialize<'de> for Msrv {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let v = String::deserialize(deserializer)?;
RustcVersion::parse(&v)
.map(|v| Msrv { stack: vec![v] })
.map_err(|_| serde::de::Error::custom("not a valid Rust version"))
}
}
impl Msrv {
pub fn empty() -> Msrv {
Msrv { stack: Vec::new() }
}
pub fn read_cargo(&mut self, sess: &Session) {
let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION")
.ok()
.and_then(|v| RustcVersion::parse(&v).ok());
match (self.current(), cargo_msrv) {
(None, Some(cargo_msrv)) => self.stack = vec![cargo_msrv],
(Some(clippy_msrv), Some(cargo_msrv)) => {
if clippy_msrv != cargo_msrv {
sess.warn(format!(
"the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
));
}
},
_ => {},
}
}
pub fn current(&self) -> Option<RustcVersion> {
self.stack.last().copied()
}
pub fn meets(&self, required: RustcVersion) -> bool {
self.current().map_or(true, |version| version.meets(required))
}
fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option<RustcVersion> {
if let Some(msrv_attr) = get_unique_attr(sess, attrs, "msrv") {
if let Some(msrv) = msrv_attr.value_str() {
if let Ok(version) = RustcVersion::parse(msrv.as_str()) {
return Some(version);
}
sess.span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version"));
} else {
sess.span_err(msrv_attr.span, "bad clippy attribute");
}
}
None
}
pub fn enter_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) {
if let Some(version) = Self::parse_attr(sess, attrs) {
self.stack.push(version);
}
}
pub fn exit_lint_attrs(&mut self, sess: &Session, attrs: &[Attribute]) {
if Self::parse_attr(sess, attrs).is_some() {
self.stack.pop();
}
}
}

View file

@ -4,16 +4,13 @@
//! Whenever possible, please consider diagnostic items over hardcoded paths.
//! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.
#[cfg(feature = "internal")]
pub const APPLICABILITY: [&str; 2] = ["rustc_lint_defs", "Applicability"];
#[cfg(feature = "internal")]
pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [
["rustc_lint_defs", "Applicability", "Unspecified"],
["rustc_lint_defs", "Applicability", "HasPlaceholders"],
["rustc_lint_defs", "Applicability", "MaybeIncorrect"],
["rustc_lint_defs", "Applicability", "MachineApplicable"],
];
#[cfg(feature = "internal")]
pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"];
pub const BINARYHEAP_ITER: [&str; 5] = ["alloc", "collections", "binary_heap", "BinaryHeap", "iter"];
pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"];
@ -25,9 +22,7 @@ pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "
pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"];
pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"];
#[cfg(feature = "internal")]
pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
#[cfg(feature = "internal")]
pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"];
pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"];
@ -38,22 +33,15 @@ pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWri
pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"];
pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"];
pub const HASHSET_ITER: [&str; 6] = ["std", "collections", "hash", "set", "HashSet", "iter"];
#[cfg(feature = "internal")]
pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
#[cfg(feature = "internal")]
pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
#[cfg(feature = "internal")]
pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
#[cfg(feature = "internal")]
pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
#[cfg(feature = "internal")]
pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"];
#[cfg(feature = "internal")]
pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
#[cfg(feature = "internal")]
pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"];
pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"];
pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"];
@ -86,17 +74,11 @@ pub const STR_CHARS: [&str; 4] = ["core", "str", "<impl str>", "chars"];
pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"];
pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
#[cfg(feature = "internal")]
pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"];
#[cfg(feature = "internal")]
pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"];
#[cfg(feature = "internal")]
pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"];
#[cfg(feature = "internal")]
pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"];
#[cfg(feature = "internal")]
pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
#[cfg(feature = "internal")]
pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"];
@ -112,6 +94,7 @@ pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"];
pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"];
pub const WAKER: [&str; 4] = ["core", "task", "wake", "Waker"];
pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
#[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so

View file

@ -3,7 +3,7 @@
// of terminologies might not be relevant in the context of Clippy. Note that its behavior might
// differ from the time of `rustc` even if the name stays the same.
use crate::msrvs::Msrv;
use clippy_config::msrvs::Msrv;
use hir::LangItem;
use rustc_attr::StableSince;
use rustc_const_eval::transform::check_consts::ConstCx;

View file

@ -8,7 +8,7 @@ use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
use rustc_lint::{LateContext, LintContext};
use rustc_session::Session;
use rustc_span::source_map::{original_sp, SourceMap};
use rustc_span::{hygiene, BytePos, SourceFileAndLine, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP};
use rustc_span::{hygiene, BytePos, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, DUMMY_SP};
use std::borrow::Cow;
use std::ops::Range;
@ -108,7 +108,7 @@ fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePo
/// Extends the span to the beginning of the spans line, incl. whitespaces.
///
/// ```rust
/// ```no_run
/// let x = ();
/// // ^^
/// // will be converted to

View file

@ -14,7 +14,7 @@ impl StrIndex {
/// Returns the index of the character after the first camel-case component of `s`.
///
/// ```
/// ```no_run
/// # use clippy_utils::str_utils::{camel_case_until, StrIndex};
/// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
/// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
@ -58,7 +58,7 @@ pub fn camel_case_until(s: &str) -> StrIndex {
/// Returns index of the first camel-case component of `s`.
///
/// ```
/// ```no_run
/// # use clippy_utils::str_utils::{camel_case_start, StrIndex};
/// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
/// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
@ -73,7 +73,7 @@ pub fn camel_case_start(s: &str) -> StrIndex {
/// Returns `StrIndex` of the last camel-case component of `s[idx..]`.
///
/// ```
/// ```no_run
/// # use clippy_utils::str_utils::{camel_case_start_from_idx, StrIndex};
/// assert_eq!(camel_case_start_from_idx("AbcDef", 0), StrIndex::new(0, 0));
/// assert_eq!(camel_case_start_from_idx("AbcDef", 1), StrIndex::new(3, 3));
@ -122,7 +122,7 @@ pub fn camel_case_start_from_idx(s: &str, start_idx: usize) -> StrIndex {
/// Get the indexes of camel case components of a string `s`
///
/// ```
/// ```no_run
/// # use clippy_utils::str_utils::{camel_case_indices, StrIndex};
/// assert_eq!(
/// camel_case_indices("AbcDef"),
@ -149,7 +149,7 @@ pub fn camel_case_indices(s: &str) -> Vec<StrIndex> {
/// Split camel case string into a vector of its components
///
/// ```
/// ```no_run
/// # use clippy_utils::str_utils::{camel_case_split, StrIndex};
/// assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]);
/// ```
@ -181,7 +181,7 @@ impl StrCount {
/// Returns the number of chars that match from the start
///
/// ```
/// ```no_run
/// # use clippy_utils::str_utils::{count_match_start, StrCount};
/// assert_eq!(count_match_start("hello_mouse", "hello_penguin"), StrCount::new(6, 6));
/// assert_eq!(count_match_start("hello_clippy", "bye_bugs"), StrCount::new(0, 0));
@ -207,7 +207,7 @@ pub fn count_match_start(str1: &str, str2: &str) -> StrCount {
/// Returns the number of chars and bytes that match from the end
///
/// ```
/// ```no_run
/// # use clippy_utils::str_utils::{count_match_end, StrCount};
/// assert_eq!(count_match_end("hello_cat", "bye_cat"), StrCount::new(4, 4));
/// assert_eq!(count_match_end("if_item_thing", "enum_value"), StrCount::new(0, 0));
@ -237,7 +237,7 @@ pub fn count_match_end(str1: &str, str2: &str) -> StrCount {
}
/// Returns a `snake_case` version of the input
/// ```
/// ```no_run
/// use clippy_utils::str_utils::to_snake_case;
/// assert_eq!(to_snake_case("AbcDef"), "abc_def");
/// assert_eq!(to_snake_case("ABCD"), "a_b_c_d");
@ -260,7 +260,7 @@ pub fn to_snake_case(name: &str) -> String {
s
}
/// Returns a `CamelCase` version of the input
/// ```
/// ```no_run
/// use clippy_utils::str_utils::to_camel_case;
/// assert_eq!(to_camel_case("abc_def"), "AbcDef");
/// assert_eq!(to_camel_case("a_b_c_d"), "ABCD");

View file

@ -465,7 +465,10 @@ forward_binop_impls_to_ref!(impl Sub, sub for Sugg<'_>, type Output = Sugg<'stat
impl Neg for Sugg<'_> {
type Output = Sugg<'static>;
fn neg(self) -> Sugg<'static> {
make_unop("-", self)
match &self {
Self::BinOp(AssocOp::As, ..) => Sugg::MaybeParen(format!("-({self})").into()),
_ => make_unop("-", self),
}
}
}