about summary refs log tree commit diff
path: root/clippy_utils/src
diff options
context:
space:
mode:
Diffstat (limited to 'clippy_utils/src')
-rw-r--r--clippy_utils/src/attrs.rs2
-rw-r--r--clippy_utils/src/eager_or_lazy.rs7
-rw-r--r--clippy_utils/src/msrvs.rs1
-rw-r--r--clippy_utils/src/paths.rs1
-rw-r--r--clippy_utils/src/qualify_min_const_fn.rs7
-rw-r--r--clippy_utils/src/source.rs42
-rw-r--r--clippy_utils/src/sugg.rs10
-rw-r--r--clippy_utils/src/ty.rs63
-rw-r--r--clippy_utils/src/visitors.rs4
9 files changed, 88 insertions, 49 deletions
diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs
index bc3d774540a..b4ad42a5027 100644
--- a/clippy_utils/src/attrs.rs
+++ b/clippy_utils/src/attrs.rs
@@ -146,7 +146,7 @@ pub fn get_unique_attr<'a>(
 /// Return true if the attributes contain any of `proc_macro`,
 /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise
 pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool {
-    attrs.iter().any(|attr| attr.is_proc_macro_attr())
+    attrs.iter().any(rustc_ast::Attribute::is_proc_macro_attr)
 }
 
 /// Return true if the attributes contain `#[doc(hidden)]`
diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs
index babbc7294a1..28c85717061 100644
--- a/clippy_utils/src/eager_or_lazy.rs
+++ b/clippy_utils/src/eager_or_lazy.rs
@@ -199,10 +199,9 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 },
 
                 // Memory allocation, custom operator, loop, or call to an unknown function
-                ExprKind::Unary(..)
-                | ExprKind::Binary(..)
-                | ExprKind::Loop(..)
-                | ExprKind::Call(..) => self.eagerness = Lazy,
+                ExprKind::Unary(..) | ExprKind::Binary(..) | ExprKind::Loop(..) | ExprKind::Call(..) => {
+                    self.eagerness = Lazy;
+                },
 
                 ExprKind::ConstBlock(_)
                 | ExprKind::Array(_)
diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs
index dbf9f3b621d..e05de2dc99c 100644
--- a/clippy_utils/src/msrvs.rs
+++ b/clippy_utils/src/msrvs.rs
@@ -19,6 +19,7 @@ macro_rules! msrv_aliases {
 
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
+    1,68,0 { PATH_MAIN_SEPARATOR_STR }
     1,65,0 { LET_ELSE }
     1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
     1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs
index 4aae0f7284e..c919575bfe9 100644
--- a/clippy_utils/src/paths.rs
+++ b/clippy_utils/src/paths.rs
@@ -67,6 +67,7 @@ pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard
 pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockReadGuard"];
 pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"];
 pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
+pub const PATH_MAIN_SEPARATOR: [&str; 3] = ["std", "path", "MAIN_SEPARATOR"];
 pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
 pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekable"];
 pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs
index 9f6adf3e3fa..d66640ba0b7 100644
--- a/clippy_utils/src/qualify_min_const_fn.rs
+++ b/clippy_utils/src/qualify_min_const_fn.rs
@@ -176,9 +176,10 @@ fn check_rvalue<'tcx>(
             // FIXME(dyn-star)
             unimplemented!()
         },
-        Rvalue::Cast(CastKind::Transmute, _, _) => {
-            Err((span, "transmute can attempt to turn pointers into integers, so is unstable in const fn".into()))
-        },
+        Rvalue::Cast(CastKind::Transmute, _, _) => Err((
+            span,
+            "transmute can attempt to turn pointers into integers, so is unstable in const fn".into(),
+        )),
         // binops are fine on integers
         Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
             check_operand(tcx, lhs, span, body)?;
diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs
index cd5dcfdaca3..62fa37660fa 100644
--- a/clippy_utils/src/source.rs
+++ b/clippy_utils/src/source.rs
@@ -12,24 +12,21 @@ use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP};
 use std::borrow::Cow;
 
 /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
-/// Also takes an `Option<String>` which can be put inside the braces.
-pub fn expr_block<'a, T: LintContext>(
+pub fn expr_block<T: LintContext>(
     cx: &T,
     expr: &Expr<'_>,
-    option: Option<String>,
-    default: &'a str,
+    outer: SyntaxContext,
+    default: &str,
     indent_relative_to: Option<Span>,
-) -> Cow<'a, str> {
-    let code = snippet_block(cx, expr.span, default, indent_relative_to);
-    let string = option.unwrap_or_default();
-    if expr.span.from_expansion() {
-        Cow::Owned(format!("{{ {} }}", snippet_with_macro_callsite(cx, expr.span, default)))
+    app: &mut Applicability,
+) -> String {
+    let (code, from_macro) = snippet_block_with_context(cx, expr.span, outer, default, indent_relative_to, app);
+    if from_macro {
+        format!("{{ {code} }}")
     } else if let ExprKind::Block(_, _) = expr.kind {
-        Cow::Owned(format!("{code}{string}"))
-    } else if string.is_empty() {
-        Cow::Owned(format!("{{ {code} }}"))
+        format!("{code}")
     } else {
-        Cow::Owned(format!("{{\n{code};\n{string}\n}}"))
+        format!("{{ {code} }}")
     }
 }
 
@@ -229,12 +226,6 @@ fn snippet_with_applicability_sess<'a>(
     )
 }
 
-/// Same as `snippet`, but should only be used when it's clear that the input span is
-/// not a macro argument.
-pub fn snippet_with_macro_callsite<'a, T: LintContext>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
-    snippet(cx, span.source_callsite(), default)
-}
-
 /// Converts a span to a code snippet. Returns `None` if not available.
 pub fn snippet_opt(cx: &impl LintContext, span: Span) -> Option<String> {
     snippet_opt_sess(cx.sess(), span)
@@ -303,6 +294,19 @@ pub fn snippet_block_with_applicability<'a>(
     reindent_multiline(snip, true, indent)
 }
 
+pub fn snippet_block_with_context<'a>(
+    cx: &impl LintContext,
+    span: Span,
+    outer: SyntaxContext,
+    default: &'a str,
+    indent_relative_to: Option<Span>,
+    app: &mut Applicability,
+) -> (Cow<'a, str>, bool) {
+    let (snip, from_macro) = snippet_with_context(cx, span, outer, default, app);
+    let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
+    (reindent_multiline(snip, true, indent), from_macro)
+}
+
 /// Same as `snippet_with_applicability`, but first walks the span up to the given context. This
 /// will result in the macro call, rather then the expansion, if the span is from a child context.
 /// If the span is not from a child context, it will be used directly instead.
diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs
index 44cb5d5756a..a5a4a921d94 100644
--- a/clippy_utils/src/sugg.rs
+++ b/clippy_utils/src/sugg.rs
@@ -1,9 +1,7 @@
 //! Contains utility functions to generate suggestions.
 #![deny(clippy::missing_docs_in_private_items)]
 
-use crate::source::{
-    snippet, snippet_opt, snippet_with_applicability, snippet_with_context, snippet_with_macro_callsite,
-};
+use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_with_context};
 use crate::ty::expr_sig;
 use crate::{get_parent_expr_for_hir, higher};
 use rustc_ast::util::parser::AssocOp;
@@ -89,12 +87,6 @@ impl<'a> Sugg<'a> {
         })
     }
 
-    /// Same as `hir`, but will use the pre expansion span if the `expr` was in a macro.
-    pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self {
-        let get_snippet = |span| snippet_with_macro_callsite(cx, span, default);
-        Self::hir_from_snippet(expr, get_snippet)
-    }
-
     /// Same as `hir`, but first walks the span up to the given context. This will result in the
     /// macro call, rather then the expansion, if the span is from a child context. If the span is
     /// not from a child context, it will be used directly instead.
diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs
index e0ea3952785..0b47234647f 100644
--- a/clippy_utils/src/ty.rs
+++ b/clippy_utils/src/ty.rs
@@ -16,9 +16,9 @@ use rustc_infer::infer::{
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::{
-    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind,
-    Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
-    UintTy, VariantDef, VariantDiscr,
+    self, layout::ValidityRequirement, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv,
+    Predicate, PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+    TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind};
 use rustc_span::symbol::Ident;
@@ -538,13 +538,12 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
 }
 
 /// Checks if a given type looks safe to be uninitialized.
-pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
-    match *ty.kind() {
-        ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component),
-        ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
-        ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did()),
-        _ => false,
-    }
+pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    cx.tcx
+        .check_validity_requirement((ValidityRequirement::Uninit, cx.param_env.and(ty)))
+        // For types containing generic parameters we cannot get a layout to check.
+        // Therefore, we are conservative and assume that they don't allow uninit.
+        .unwrap_or(false)
 }
 
 /// Gets an iterator over all predicates which apply to the given item.
@@ -1121,3 +1120,47 @@ pub fn make_normalized_projection<'tcx>(
     }
     helper(tcx, param_env, make_projection(tcx, container_id, assoc_ty, substs)?)
 }
+
+/// Check if given type has inner mutability such as [`std::cell::Cell`] or [`std::cell::RefCell`]
+/// etc.
+pub fn is_interior_mut_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    match *ty.kind() {
+        ty::Ref(_, inner_ty, mutbl) => mutbl == Mutability::Mut || is_interior_mut_ty(cx, inner_ty),
+        ty::Slice(inner_ty) => is_interior_mut_ty(cx, inner_ty),
+        ty::Array(inner_ty, size) => {
+            size.try_eval_target_usize(cx.tcx, cx.param_env)
+                .map_or(true, |u| u != 0)
+                && is_interior_mut_ty(cx, inner_ty)
+        },
+        ty::Tuple(fields) => fields.iter().any(|ty| is_interior_mut_ty(cx, ty)),
+        ty::Adt(def, substs) => {
+            // Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
+            // that of their type parameters.  Note: we don't include `HashSet` and `HashMap`
+            // because they have no impl for `Hash` or `Ord`.
+            let def_id = def.did();
+            let is_std_collection = [
+                sym::Option,
+                sym::Result,
+                sym::LinkedList,
+                sym::Vec,
+                sym::VecDeque,
+                sym::BTreeMap,
+                sym::BTreeSet,
+                sym::Rc,
+                sym::Arc,
+            ]
+            .iter()
+            .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def_id));
+            let is_box = Some(def_id) == cx.tcx.lang_items().owned_box();
+            if is_std_collection || is_box {
+                // The type is mutable if any of its type parameters are
+                substs.types().any(|ty| is_interior_mut_ty(cx, ty))
+            } else {
+                !ty.has_escaping_bound_vars()
+                    && cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
+                    && !ty.is_freeze(cx.tcx, cx.param_env)
+            }
+        },
+        _ => false,
+    }
+}
diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs
index 86a93f64fb7..1dc19bac984 100644
--- a/clippy_utils/src/visitors.rs
+++ b/clippy_utils/src/visitors.rs
@@ -599,9 +599,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
             | ExprKind::Let(&Let { init: e, .. }) => {
                 helper(typeck, false, e, f)?;
             },
-            ExprKind::Block(&Block { expr: Some(e), .. }, _)
-            | ExprKind::Cast(e, _)
-            | ExprKind::Unary(_, e) => {
+            ExprKind::Block(&Block { expr: Some(e), .. }, _) | ExprKind::Cast(e, _) | ExprKind::Unary(_, e) => {
                 helper(typeck, true, e, f)?;
             },
             ExprKind::Call(callee, args) => {