about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2020-08-04 14:24:13 +0100
committerDavid Wood <david@davidtw.co>2020-08-17 13:55:05 +0100
commitf1ce2948dba9b314b3f0205a6e9b125bdf186b8e (patch)
treefe2143aa15635f00e1fdc921c410a451da01a56b
parentdde93c9ba61e441bcafab84a1e42cddb32aa0178 (diff)
downloadrust-f1ce2948dba9b314b3f0205a6e9b125bdf186b8e.tar.gz
rust-f1ce2948dba9b314b3f0205a6e9b125bdf186b8e.zip
clippy: support `QPath::LangItem`
This commit updates clippy with the introduction of `QPath::LangItem` so
that it still compiles.

Signed-off-by: David Wood <david@davidtw.co>
-rw-r--r--src/tools/clippy/clippy_lints/src/default_trait_access.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/match_on_vec_items.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/try_err.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/types.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/higher.rs98
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/hir_utils.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/inspector.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/paths.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/sugg.rs8
-rw-r--r--src/tools/clippy/tests/ui/author/for_loop.stdout16
20 files changed, 117 insertions, 130 deletions
diff --git a/src/tools/clippy/clippy_lints/src/default_trait_access.rs b/src/tools/clippy/clippy_lints/src/default_trait_access.rs
index 874e19d9e9f..067ea903bdd 100644
--- a/src/tools/clippy/clippy_lints/src/default_trait_access.rs
+++ b/src/tools/clippy/clippy_lints/src/default_trait_access.rs
@@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess {
                             );
                          }
                     },
-                    QPath::TypeRelative(..) => {},
+                    QPath::TypeRelative(..) | QPath::LangItem(..) => {},
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index a1f58e54ae3..90b1a529be7 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -89,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Index(ref array, ref index) = &expr.kind {
             let ty = cx.typeck_results().expr_ty(array);
-            if let Some(range) = higher::range(cx, index) {
+            if let Some(range) = higher::range(index) {
                 // Ranged indexes, i.e., &x[n..m], &x[n..], &x[..n] and &x[..]
                 if let ty::Array(_, s) = ty.kind {
                     let size: u128 = if let Some(size) = s.try_eval_usize(cx.tcx, cx.param_env) {
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index e511d3ea330..129abd7d897 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -171,7 +171,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                 Finite
             }
         },
-        ExprKind::Struct(..) => higher::range(cx, expr).map_or(false, |r| r.end.is_none()).into(),
+        ExprKind::Struct(..) => higher::range(expr).map_or(false, |r| r.end.is_none()).into(),
         _ => Finite,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 00d0b8b4e5b..e5daa30f8ca 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -262,7 +262,7 @@ fn check_len(
 fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     /// Special case ranges until `range_is_empty` is stabilized. See issue 3807.
     fn should_skip_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-        higher::range(cx, expr).map_or(false, |_| {
+        higher::range(expr).map_or(false, |_| {
             !cx.tcx
                 .features()
                 .declared_lib_features
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index 8352a8a3d2c..8ffcd417d1d 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -1003,7 +1003,7 @@ fn detect_manual_memcpy<'tcx>(
         start: Some(start),
         end: Some(end),
         limits,
-    }) = higher::range(cx, arg)
+    }) = higher::range(arg)
     {
         // the var must be a single name
         if let PatKind::Binding(_, canonical_id, _, _) = pat.kind {
@@ -1177,7 +1177,7 @@ fn check_for_loop_range<'tcx>(
         start: Some(start),
         ref end,
         limits,
-    }) = higher::range(cx, arg)
+    }) = higher::range(arg)
     {
         // the var must be a single name
         if let PatKind::Binding(_, canonical_id, ident, _) = pat.kind {
@@ -1679,7 +1679,7 @@ fn check_for_mut_range_bound(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'
         start: Some(start),
         end: Some(end),
         ..
-    }) = higher::range(cx, arg)
+    }) = higher::range(arg)
     {
         let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
         if mut_ids[0].is_some() || mut_ids[1].is_some() {
diff --git a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
index 4f8f2cb171d..faa20687ef6 100644
--- a/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
+++ b/src/tools/clippy/clippy_lints/src/match_on_vec_items.rs
@@ -1,7 +1,8 @@
-use crate::utils::{self, is_type_diagnostic_item, match_type, snippet, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{is_type_diagnostic_item, is_type_lang_item, snippet, span_lint_and_sugg};
+use crate::utils::walk_ptrs_ty;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, MatchSource};
+use rustc_hir::{Expr, ExprKind, LangItem, MatchSource};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -96,5 +97,5 @@ fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
     let ty = walk_ptrs_ty(ty);
-    match_type(cx, ty, &utils::paths::RANGE_FULL)
+    is_type_lang_item(cx, ty, LangItem::RangeFull)
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 570ae66d595..2265a188855 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -2271,7 +2271,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_
         if_chain! {
             if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
             if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
-                = higher::range(cx, index_expr);
+                = higher::range(index_expr);
             if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
             if let ast::LitKind::Int(start_idx, _) = start_lit.node;
             then {
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 26a1c32b6b3..482a563572d 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -433,6 +433,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
             return;
         }
         let binding = match expr.kind {
+            ExprKind::Path(hir::QPath::LangItem(..)) => None,
             ExprKind::Path(ref qpath) => {
                 let binding = last_path_segment(qpath).ident.as_str();
                 if binding.starts_with('_') &&
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index f88075798ca..7a75fc125d0 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -147,7 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges {
                     if let ExprKind::MethodCall(ref iter_path, _, ref iter_args , _) = *iter;
                     if iter_path.ident.name == sym!(iter);
                     // range expression in `.zip()` call: `0..x.len()`
-                    if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(cx, zip_arg);
+                    if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(zip_arg);
                     if is_integer_const(cx, start, 0);
                     // `.len()` call
                     if let ExprKind::MethodCall(ref len_path, _, ref len_args, _) = end.kind;
@@ -180,7 +180,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
             start,
             end: Some(end),
             limits: RangeLimits::HalfOpen
-        }) = higher::range(cx, expr);
+        }) = higher::range(expr);
         if let Some(y) = y_plus_one(cx, end);
         then {
             let span = if expr.span.from_expansion() {
@@ -225,7 +225,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
 // inclusive range minus one: `x..=(y-1)`
 fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
-        if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(cx, expr);
+        if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::range(expr);
         if let Some(y) = y_minus_one(cx, end);
         then {
             span_lint_and_then(
@@ -279,7 +279,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
     }
 
     if_chain! {
-        if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(cx, expr);
+        if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(expr);
         let ty = cx.typeck_results().expr_ty(start);
         if let ty::Int(_) | ty::Uint(_) = ty.kind;
         if let Some((start_idx, _)) = constant(cx, cx.typeck_results(), start);
diff --git a/src/tools/clippy/clippy_lints/src/try_err.rs b/src/tools/clippy/clippy_lints/src/try_err.rs
index 3bd73d9f21a..a74104e9282 100644
--- a/src/tools/clippy/clippy_lints/src/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/try_err.rs
@@ -1,10 +1,10 @@
 use crate::utils::{
-    is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite,
-    span_lint_and_sugg,
+    is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet,
+    snippet_with_macro_callsite, span_lint_and_sugg,
 };
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, MatchSource};
+use rustc_hir::{Expr, ExprKind, QPath, LangItem, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
             if let ExprKind::Match(ref match_arg, _, MatchSource::TryDesugar) = expr.kind;
             if let ExprKind::Call(ref match_fun, ref try_args) = match_arg.kind;
             if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
-            if match_qpath(match_fun_path, &paths::TRY_INTO_RESULT);
+            if matches!(match_fun_path, QPath::LangItem(LangItem::TryIntoResult, _));
             if let Some(ref try_arg) = try_args.get(0);
             if let ExprKind::Call(ref err_fun, ref err_args) = try_arg.kind;
             if let Some(ref err_arg) = err_args.get(0);
diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs
index c3dea447521..d1a7886a47e 100644
--- a/src/tools/clippy/clippy_lints/src/types.rs
+++ b/src/tools/clippy/clippy_lints/src/types.rs
@@ -475,6 +475,7 @@ impl Types {
                             }
                         }
                     },
+                    QPath::LangItem(..) => {},
                 }
             },
             TyKind::Rptr(ref lt, ref mut_ty) => self.check_ty_rptr(cx, hir_ty, is_local, lt, mut_ty),
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 1580f657d77..43166d26787 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -1,4 +1,4 @@
-use crate::utils::{is_try, match_qpath, match_trait_method, paths, span_lint};
+use crate::utils::{is_try, match_trait_method, paths, span_lint};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -42,10 +42,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
         match expr.kind {
             hir::ExprKind::Match(ref res, _, _) if is_try(expr).is_some() => {
                 if let hir::ExprKind::Call(ref func, ref args) = res.kind {
-                    if let hir::ExprKind::Path(ref path) = func.kind {
-                        if match_qpath(path, &paths::TRY_INTO_RESULT) && args.len() == 1 {
-                            check_method_call(cx, &args[0], expr);
-                        }
+                    if matches!(
+                        func.kind,
+                        hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryIntoResult, _))
+                    ) {
+                        check_method_call(cx, &args[0], expr);
                     }
                 } else {
                     check_method_call(cx, res, expr);
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 128fa87a162..9b7a268c628 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -175,9 +175,19 @@ impl PrintVisitor {
     }
 
     fn print_qpath(&mut self, path: &QPath<'_>) {
-        print!("    if match_qpath({}, &[", self.current);
-        print_path(path, &mut true);
-        println!("]);");
+        match  *path {
+            QPath::LangItem(lang_item, _) => {
+                println!(
+                    "    if matches!({}, QPath::LangItem(LangItem::{:?}, _));",
+                   self.current, lang_item,
+                );
+            },
+            _ => {
+                print!("    if match_qpath({}, &[", self.current);
+                print_path(path, &mut true);
+                println!("]);");
+            },
+        }
     }
 }
 
@@ -760,5 +770,6 @@ fn print_path(path: &QPath<'_>, first: &mut bool) {
             },
             ref other => print!("/* unimplemented: {:?}*/", other),
         },
+        QPath::LangItem(..) => panic!("print_path: called for lang item qpath"),
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/higher.rs b/src/tools/clippy/clippy_lints/src/utils/higher.rs
index f81a132c7e7..ba15456014d 100644
--- a/src/tools/clippy/clippy_lints/src/utils/higher.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/higher.rs
@@ -3,12 +3,11 @@
 
 #![deny(clippy::missing_docs_in_private_items)]
 
-use crate::utils::{is_expn_of, match_def_path, match_qpath, paths};
+use crate::utils::{is_expn_of, match_def_path, paths};
 use if_chain::if_chain;
 use rustc_ast::ast;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_middle::ty;
 
 /// Converts a hir binary operator to the corresponding `ast` type.
 #[must_use]
@@ -47,7 +46,7 @@ pub struct Range<'a> {
 }
 
 /// Higher a `hir` range to something similar to `ast::ExprKind::Range`.
-pub fn range<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
+pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
     /// Finds the field named `name` in the field. Always return `Some` for
     /// convenience.
     fn get_field<'c>(name: &str, fields: &'c [hir::Field<'_>]) -> Option<&'c hir::Expr<'c>> {
@@ -56,94 +55,43 @@ pub fn range<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a hir::Expr<'_>) -> Optio
         Some(expr)
     }
 
-    let def_path = match cx.typeck_results().expr_ty(expr).kind {
-        ty::Adt(def, _) => cx.tcx.def_path(def.did),
-        _ => return None,
-    };
-
-    // sanity checks for std::ops::RangeXXXX
-    if def_path.data.len() != 3 {
-        return None;
-    }
-    if def_path.data.get(0)?.data.as_symbol() != sym!(ops) {
-        return None;
-    }
-    if def_path.data.get(1)?.data.as_symbol() != sym!(range) {
-        return None;
-    }
-    let type_name = def_path.data.get(2)?.data.as_symbol();
-    let range_types = [
-        "RangeFrom",
-        "RangeFull",
-        "RangeInclusive",
-        "Range",
-        "RangeTo",
-        "RangeToInclusive",
-    ];
-    if !range_types.contains(&&*type_name.as_str()) {
-        return None;
-    }
-
-    // The range syntax is expanded to literal paths starting with `core` or `std`
-    // depending on
-    // `#[no_std]`. Testing both instead of resolving the paths.
-
     match expr.kind {
-        hir::ExprKind::Path(ref path) => {
-            if match_qpath(path, &paths::RANGE_FULL_STD) || match_qpath(path, &paths::RANGE_FULL) {
-                Some(Range {
+        hir::ExprKind::Call(ref path, ref args) if matches!(
+            path.kind,
+            hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
+        ) => Some(Range {
+            start: Some(&args[0]),
+            end: Some(&args[1]),
+            limits: ast::RangeLimits::Closed,
+        }),
+        hir::ExprKind::Struct(ref path, ref fields, None) => {
+            match path {
+                hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
                     start: None,
                     end: None,
                     limits: ast::RangeLimits::HalfOpen,
-                })
-            } else {
-                None
-            }
-        },
-        hir::ExprKind::Call(ref path, ref args) => {
-            if let hir::ExprKind::Path(ref path) = path.kind {
-                if match_qpath(path, &paths::RANGE_INCLUSIVE_STD_NEW) || match_qpath(path, &paths::RANGE_INCLUSIVE_NEW)
-                {
-                    Some(Range {
-                        start: Some(&args[0]),
-                        end: Some(&args[1]),
-                        limits: ast::RangeLimits::Closed,
-                    })
-                } else {
-                    None
-                }
-            } else {
-                None
-            }
-        },
-        hir::ExprKind::Struct(ref path, ref fields, None) => {
-            if match_qpath(path, &paths::RANGE_FROM_STD) || match_qpath(path, &paths::RANGE_FROM) {
-                Some(Range {
+                }),
+                hir::QPath::LangItem(hir::LangItem::RangeFrom, _) => Some(Range {
                     start: Some(get_field("start", fields)?),
                     end: None,
                     limits: ast::RangeLimits::HalfOpen,
-                })
-            } else if match_qpath(path, &paths::RANGE_STD) || match_qpath(path, &paths::RANGE) {
-                Some(Range {
+                }),
+                hir::QPath::LangItem(hir::LangItem::Range, _) => Some(Range {
                     start: Some(get_field("start", fields)?),
                     end: Some(get_field("end", fields)?),
                     limits: ast::RangeLimits::HalfOpen,
-                })
-            } else if match_qpath(path, &paths::RANGE_TO_INCLUSIVE_STD) || match_qpath(path, &paths::RANGE_TO_INCLUSIVE)
-            {
-                Some(Range {
+                }),
+                hir::QPath::LangItem(hir::LangItem::RangeToInclusive, _) => Some(Range {
                     start: None,
                     end: Some(get_field("end", fields)?),
                     limits: ast::RangeLimits::Closed,
-                })
-            } else if match_qpath(path, &paths::RANGE_TO_STD) || match_qpath(path, &paths::RANGE_TO) {
-                Some(Range {
+                }),
+                hir::QPath::LangItem(hir::LangItem::RangeTo, _) => Some(Range {
                     start: None,
                     end: Some(get_field("end", fields)?),
                     limits: ast::RangeLimits::HalfOpen,
-                })
-            } else {
-                None
+                }),
+                _ => None,
             }
         },
         _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
index 28fb6ed12a0..2eefd4a38a6 100644
--- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
@@ -3,9 +3,9 @@ use crate::utils::differing_macro_contexts;
 use rustc_ast::ast::InlineAsmTemplatePiece;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::{
-    BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FnRetTy, GenericArg,
-    GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatKind, Path, PathSegment, QPath,
-    Stmt, StmtKind, Ty, TyKind, TypeBinding,
+    BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FieldPat,
+    FnRetTy, GenericArg, GenericArgs, Guard, InlineAsmOperand, Lifetime, LifetimeName, ParamName,
+    Pat, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
 };
 use rustc_lint::LateContext;
 use rustc_middle::ich::StableHashingContextProvider;
@@ -185,10 +185,20 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
         left.name == right.name
     }
 
+    pub fn eq_fieldpat(&mut self, left: &FieldPat<'_>, right: &FieldPat<'_>) -> bool {
+        match (&left, &right) {
+            (FieldPat { ident: li, pat: lp, .. }, FieldPat { ident: ri, pat: rp, .. }) =>
+                li.name.as_str() == ri.name.as_str() && self.eq_pat(lp, rp),
+        }
+    }
+
     /// Checks whether two patterns are the same.
     pub fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
         match (&left.kind, &right.kind) {
             (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
+            (&PatKind::Struct(ref lp, ref la, ..), &PatKind::Struct(ref rp, ref ra, ..)) => {
+                self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_fieldpat(l, r))
+            },
             (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
             },
@@ -223,6 +233,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
             (&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => {
                 self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
             },
+            (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) =>
+                llang_item == rlang_item,
             _ => false,
         }
     }
@@ -601,6 +613,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             QPath::TypeRelative(_, ref path) => {
                 self.hash_name(path.ident.name);
             },
+            QPath::LangItem(lang_item, ..) => {
+                lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+            }
         }
         // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
     }
@@ -710,6 +725,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_ty(ty);
                     segment.ident.name.hash(&mut self.s);
                 },
+                QPath::LangItem(lang_item, ..) => {
+                    lang_item.hash(&mut self.s);
+                }
             },
             TyKind::OpaqueDef(_, arg_list) => {
                 self.hash_generic_args(arg_list);
diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs
index d8fa1fa278e..4701a3f26e6 100644
--- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs
@@ -266,6 +266,9 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
             println!("{}Relative Path, {:?}", ind, ty);
             println!("{}seg: {:?}", ind, seg);
         },
+        hir::ExprKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
+            println!("{}Lang Item Path, {:?}", ind, lang_item.name());
+        },
         hir::ExprKind::AddrOf(kind, ref muta, ref e) => {
             println!("{}AddrOf", ind);
             println!("kind: {:?}", kind);
@@ -488,6 +491,9 @@ fn print_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, indent: usize) {
             println!("{}Relative Path, {:?}", ind, ty);
             println!("{}seg: {:?}", ind, seg);
         },
+        hir::PatKind::Path(hir::QPath::LangItem(lang_item, ..)) => {
+            println!("{}Lang Item Path, {:?}", ind, lang_item.name());
+        },
         hir::PatKind::Tuple(pats, opt_dots_position) => {
             println!("{}Tuple", ind);
             if let Some(dot_position) = opt_dots_position {
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 223628cc610..a56b8203513 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -142,6 +142,14 @@ pub fn is_type_diagnostic_item(cx: &LateContext<'_>, ty: Ty<'_>, diag_item: Symb
     }
 }
 
+/// Checks if the type is equal to a lang item
+pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool {
+    match ty.kind {
+        ty::Adt(adt, _) => cx.tcx.lang_items().require(lang_item).unwrap() == adt.did,
+        _ => false,
+    }
+}
+
 /// Checks if the method call given in `expr` belongs to the given trait.
 pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
     let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
@@ -163,6 +171,7 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
     match *path {
         QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"),
         QPath::TypeRelative(_, ref seg) => seg,
+        QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
     }
 }
 
@@ -170,6 +179,7 @@ pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment
     match *path {
         QPath::Resolved(_, ref path) => path.segments.get(0),
         QPath::TypeRelative(_, ref seg) => Some(seg),
+        QPath::LangItem(..) => None,
     }
 }
 
@@ -196,6 +206,7 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
             },
             _ => false,
         },
+        QPath::LangItem(..) => false,
     }
 }
 
@@ -277,7 +288,7 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<def::Res> {
 pub fn qpath_res(cx: &LateContext<'_>, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
     match qpath {
         hir::QPath::Resolved(_, path) => path.res,
-        hir::QPath::TypeRelative(..) => {
+        hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
             if cx.tcx.has_typeck_results(id.owner.to_def_id()) {
                 cx.tcx.typeck(id.owner.to_def_id().expect_local()).qpath_res(qpath, id)
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs
index 923b319d777..9c28d63d414 100644
--- a/src/tools/clippy/clippy_lints/src/utils/paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs
@@ -84,19 +84,7 @@ pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
 pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
 pub const PTR_NULL: [&str; 2] = ["ptr", "null"];
 pub const PTR_NULL_MUT: [&str; 2] = ["ptr", "null_mut"];
-pub const RANGE: [&str; 3] = ["core", "ops", "Range"];
 pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
-pub const RANGE_FROM: [&str; 3] = ["core", "ops", "RangeFrom"];
-pub const RANGE_FROM_STD: [&str; 3] = ["std", "ops", "RangeFrom"];
-pub const RANGE_FULL: [&str; 4] = ["core", "ops", "range", "RangeFull"];
-pub const RANGE_FULL_STD: [&str; 3] = ["std", "ops", "RangeFull"];
-pub const RANGE_INCLUSIVE_NEW: [&str; 4] = ["core", "ops", "RangeInclusive", "new"];
-pub const RANGE_INCLUSIVE_STD_NEW: [&str; 4] = ["std", "ops", "RangeInclusive", "new"];
-pub const RANGE_STD: [&str; 3] = ["std", "ops", "Range"];
-pub const RANGE_TO: [&str; 3] = ["core", "ops", "RangeTo"];
-pub const RANGE_TO_INCLUSIVE: [&str; 3] = ["core", "ops", "RangeToInclusive"];
-pub const RANGE_TO_INCLUSIVE_STD: [&str; 3] = ["std", "ops", "RangeToInclusive"];
-pub const RANGE_TO_STD: [&str; 3] = ["std", "ops", "RangeTo"];
 pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
 pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
 pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"];
@@ -130,7 +118,6 @@ pub const TO_STRING: [&str; 3] = ["alloc", "string", "ToString"];
 pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
 pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
 pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
-pub const TRY_INTO_RESULT: [&str; 4] = ["std", "ops", "Try", "into_result"];
 pub const TRY_INTO_TRAIT: [&str; 3] = ["core", "convert", "TryInto"];
 pub const VEC: [&str; 3] = ["alloc", "vec", "Vec"];
 pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
diff --git a/src/tools/clippy/clippy_lints/src/utils/sugg.rs b/src/tools/clippy/clippy_lints/src/utils/sugg.rs
index 0ac7714fbeb..2955f8d8e59 100644
--- a/src/tools/clippy/clippy_lints/src/utils/sugg.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/sugg.rs
@@ -42,7 +42,7 @@ impl<'a> Sugg<'a> {
     pub fn hir_opt(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Self> {
         snippet_opt(cx, expr.span).map(|snippet| {
             let snippet = Cow::Owned(snippet);
-            Self::hir_from_snippet(cx, expr, snippet)
+            Self::hir_from_snippet(expr, snippet)
         })
     }
 
@@ -80,13 +80,13 @@ impl<'a> Sugg<'a> {
     pub fn hir_with_macro_callsite(cx: &LateContext<'_>, expr: &hir::Expr<'_>, default: &'a str) -> Self {
         let snippet = snippet_with_macro_callsite(cx, expr.span, default);
 
-        Self::hir_from_snippet(cx, expr, snippet)
+        Self::hir_from_snippet(expr, snippet)
     }
 
     /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
     /// function variants of `Sugg`, since these use different snippet functions.
-    fn hir_from_snippet(cx: &LateContext<'_>, expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
-        if let Some(range) = higher::range(cx, expr) {
+    fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
+        if let Some(range) = higher::range(expr) {
             let op = match range.limits {
                 ast::RangeLimits::HalfOpen => AssocOp::DotDot,
                 ast::RangeLimits::Closed => AssocOp::DotDotEq,
diff --git a/src/tools/clippy/tests/ui/author/for_loop.stdout b/src/tools/clippy/tests/ui/author/for_loop.stdout
index 81ede955347..3bf7607c62f 100644
--- a/src/tools/clippy/tests/ui/author/for_loop.stdout
+++ b/src/tools/clippy/tests/ui/author/for_loop.stdout
@@ -3,10 +3,10 @@ if_chain! {
     if let ExprKind::Match(ref expr1, ref arms, MatchSource::ForLoopDesugar) = expr.kind;
     if let ExprKind::Call(ref func, ref args) = expr1.kind;
     if let ExprKind::Path(ref path) = func.kind;
-    if match_qpath(path, &["{{root}}", "std", "iter", "IntoIterator", "into_iter"]);
+    if matches!(path, QPath::LangItem(LangItem::IntoIterIntoIter, _));
     if args.len() == 1;
     if let ExprKind::Struct(ref path1, ref fields, None) = args[0].kind;
-    if match_qpath(path1, &["{{root}}", "std", "ops", "Range"]);
+    if matches!(path1, QPath::LangItem(LangItem::Range, _));
     if fields.len() == 2;
     // unimplemented: field checks
     if arms.len() == 1;
@@ -20,7 +20,7 @@ if_chain! {
     if let ExprKind::Match(ref expr2, ref arms1, MatchSource::ForLoopDesugar) = e.kind;
     if let ExprKind::Call(ref func1, ref args1) = expr2.kind;
     if let ExprKind::Path(ref path2) = func1.kind;
-    if match_qpath(path2, &["{{root}}", "std", "iter", "Iterator", "next"]);
+    if matches!(path2, QPath::LangItem(LangItem::IteratorNext, _));
     if args1.len() == 1;
     if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, ref inner) = args1[0].kind;
     if let ExprKind::Path(ref path3) = inner.kind;
@@ -31,13 +31,15 @@ if_chain! {
     if match_qpath(path4, &["__next"]);
     if let ExprKind::Path(ref path5) = value.kind;
     if match_qpath(path5, &["val"]);
-    if let PatKind::TupleStruct(ref path6, ref fields1, None) = arms1[0].pat.kind;
-    if match_qpath(path6, &["{{root}}", "std", "option", "Option", "Some"]);
+    if let PatKind::Struct(ref path6, ref fields1, false) = arms1[0].pat.kind;
+    if matches!(path6, QPath::LangItem(LangItem::OptionSome, _));
     if fields1.len() == 1;
     // unimplemented: field checks
     if let ExprKind::Break(ref destination, None) = arms1[1].body.kind;
-    if let PatKind::Path(ref path7) = arms1[1].pat.kind;
-    if match_qpath(path7, &["{{root}}", "std", "option", "Option", "None"]);
+    if let PatKind::Struct(ref path7, ref fields2, false) = arms1[1].pat.kind;
+    if matches!(path7, QPath::LangItem(LangItem::OptionNone, _));
+    if fields2.len() == 0;
+    // unimplemented: field checks
     if let StmtKind::Local(ref local1) = body.stmts[2].kind;
     if let Some(ref init) = local1.init;
     if let ExprKind::Path(ref path8) = init.kind;