]> git.lizzy.rs Git - rust.git/blobdiff - clippy_utils/src/lib.rs
Auto merge of #6823 - Jarcho:diagnostic_items, r=phansch
[rust.git] / clippy_utils / src / lib.rs
index 08e260b7d94ac6da50146cb2d6a6d1c4bae6cbf8..daeced6bad483ab9f57208c71154a3b277a4ac63 100644 (file)
@@ -14,6 +14,7 @@
 extern crate rustc_hir;
 extern crate rustc_hir_pretty;
 extern crate rustc_infer;
+extern crate rustc_lexer;
 extern crate rustc_lint;
 extern crate rustc_middle;
 extern crate rustc_mir;
 use rustc_middle::ty::{self, layout::IntegerExt, DefIdTree, Ty, TyCtxt, TypeFoldable};
 use rustc_semver::RustcVersion;
 use rustc_session::Session;
-use rustc_span::hygiene::{ExpnKind, MacroKind};
+use rustc_span::hygiene::{self, ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
 use rustc_span::sym;
 use rustc_span::symbol::{kw, Symbol};
-use rustc_span::{BytePos, Pos, Span, DUMMY_SP};
+use rustc_span::{BytePos, Pos, Span, SyntaxContext, DUMMY_SP};
 use rustc_target::abi::Integer;
 use rustc_trait_selection::traits::query::normalize::AtExt;
 use smallvec::SmallVec;
@@ -494,6 +495,18 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     }
 }
 
+/// Checks whether a type can be partially moved.
+pub fn can_partially_move_ty(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    if has_drop(cx, ty) || is_copy(cx, ty) {
+        return false;
+    }
+    match ty.kind() {
+        ty::Param(_) => false,
+        ty::Adt(def, subs) => def.all_fields().any(|f| !is_copy(cx, f.ty(cx.tcx, subs))),
+        _ => true,
+    }
+}
+
 /// Returns the method names and argument list of nested method call expressions that make up
 /// `expr`. method/span lists are sorted with the most recent call first.
 pub fn method_calls<'tcx>(
@@ -784,6 +797,35 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>(
     reindent_multiline(snip, true, indent)
 }
 
+/// 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.
+///
+/// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR node
+/// would result in `box []`. If given the context of the address of expression, this function will
+/// correctly get a snippet of `vec![]`.
+pub fn snippet_with_context(
+    cx: &LateContext<'_>,
+    span: Span,
+    outer: SyntaxContext,
+    default: &'a str,
+    applicability: &mut Applicability,
+) -> Cow<'a, str> {
+    let outer_span = hygiene::walk_chain(span, outer);
+    let span = if outer_span.ctxt() == outer {
+        outer_span
+    } else {
+        // The span is from a macro argument, and the outer context is the macro using the argument
+        if *applicability != Applicability::Unspecified {
+            *applicability = Applicability::MaybeIncorrect;
+        }
+        // TODO: get the argument span.
+        span
+    };
+
+    snippet_with_applicability(cx, span, default, applicability)
+}
+
 /// Returns a new Span that extends the original Span to the first non-whitespace char of the first
 /// line.
 ///
@@ -1585,12 +1627,12 @@ pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
 /// ```
 pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
     use rustc_trait_selection::traits;
-    let predicates =
-        cx.tcx
-            .predicates_of(did)
-            .predicates
-            .iter()
-            .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
+    let predicates = cx
+        .tcx
+        .predicates_of(did)
+        .predicates
+        .iter()
+        .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
     traits::impossible_predicates(
         cx.tcx,
         traits::elaborate_predicates(cx.tcx, predicates)