about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJacherr <jwc2002@outlook.com>2024-03-19 10:41:56 +0000
committerJacher <jwc2002@outlook.com>2024-05-30 11:45:57 +0000
commite186ed2ad1bdac3190e8ff3e35331249a4527fea (patch)
treeaa3403e04a83e31946ad153f12be5b40476a683e
parent46b3264131f9e465cabba119ceccd61fe5617612 (diff)
downloadrust-e186ed2ad1bdac3190e8ff3e35331249a4527fea.tar.gz
rust-e186ed2ad1bdac3190e8ff3e35331249a4527fea.zip
check return type of get and indexing
-rw-r--r--clippy_lints/src/indexing_slicing.rs40
-rw-r--r--clippy_lints/src/iter_without_into_iter.rs4
-rw-r--r--clippy_utils/src/ty.rs30
-rw-r--r--tests/ui/indexing_slicing_slice.rs38
4 files changed, 94 insertions, 18 deletions
diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs
index 43797215ca5..7dee30547a0 100644
--- a/clippy_lints/src/indexing_slicing.rs
+++ b/clippy_lints/src/indexing_slicing.rs
@@ -3,12 +3,13 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::higher;
-use clippy_utils::ty::{adt_has_inherent_method, deref_chain};
+use clippy_utils::ty::{deref_chain, get_adt_inherent_method};
 use rustc_ast::ast::RangeLimits;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -111,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
             && deref.any(|l| {
                 l.peel_refs().is_slice()
                     || l.peel_refs().is_array()
-                    || adt_has_inherent_method(cx, l.peel_refs(), sym!(get))
+                    || ty_has_appliciable_get_function(cx, l.peel_refs(), expr_ty, expr)
             })
         {
             let note = "the suggestion might not be applicable in constant blocks";
@@ -240,3 +241,36 @@ fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u1
 
     (start, end)
 }
+
+/// Checks if the output Ty of the `get` method on this Ty (if any) matches the Ty returned by the
+/// indexing operation (if any).
+fn ty_has_appliciable_get_function<'tcx>(
+    cx: &LateContext<'tcx>,
+    ty: Ty<'tcx>,
+    array_ty: Ty<'tcx>,
+    index_expr: &Expr<'_>,
+) -> bool {
+    if let ty::Adt(_, array_args) = array_ty.kind()
+        && let Some(get_output_ty) = get_adt_inherent_method(cx, ty, sym!(get)).map(|m| {
+            cx.tcx
+                .fn_sig(m.def_id)
+                .instantiate(cx.tcx, array_args)
+                .output()
+                .skip_binder()
+        })
+        && let ty::Adt(def, args) = get_output_ty.kind()
+        && cx.tcx.is_diagnostic_item(sym::Option, def.0.did)
+        && let Some(option_generic_param) = args.get(0)
+        && let generic_ty = option_generic_param.expect_ty().peel_refs()
+        && let _ = println!(
+            "{}, {}",
+            cx.typeck_results().expr_ty(index_expr).peel_refs(),
+            generic_ty.peel_refs()
+        )
+        && cx.typeck_results().expr_ty(index_expr).peel_refs() == generic_ty.peel_refs()
+    {
+        true
+    } else {
+        false
+    }
+}
diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs
index 02fefd1b6a1..6b03f2597b0 100644
--- a/clippy_lints/src/iter_without_into_iter.rs
+++ b/clippy_lints/src/iter_without_into_iter.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_parent_as_impl;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::{adt_has_inherent_method, deref_chain, implements_trait, make_normalized_projection};
+use clippy_utils::ty::{deref_chain, get_adt_inherent_method, implements_trait, make_normalized_projection};
 use rustc_ast::Mutability;
 use rustc_errors::Applicability;
 use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind};
@@ -139,7 +139,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
             }
             && !deref_chain(cx, ty).any(|ty| {
                 // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method
-                ty.peel_refs().is_slice() || adt_has_inherent_method(cx, ty, expected_method_name)
+                ty.peel_refs().is_slice() || get_adt_inherent_method(cx, ty, expected_method_name).is_some()
             })
             && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| {
                 if item.ident.name == sym!(IntoIter) {
diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs
index 7dda01102c2..90360e85d8d 100644
--- a/clippy_utils/src/ty.rs
+++ b/clippy_utils/src/ty.rs
@@ -17,9 +17,9 @@ use rustc_middle::mir::ConstValue;
 use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
-    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
-    GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
+    self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind,
+    GenericArgsRef, GenericParamDefKind, IntTy, List, ParamEnv, Region, RegionKind, ToPredicate, TraitRef, Ty, TyCtxt,
+    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
@@ -1345,16 +1345,22 @@ pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl
 /// Checks if a Ty<'_> has some inherent method Symbol.
 /// This does not look for impls in the type's `Deref::Target` type.
 /// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`.
-pub fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
+pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> {
     if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) {
-        cx.tcx.inherent_impls(ty_did).into_iter().flatten().any(|&did| {
-            cx.tcx
-                .associated_items(did)
-                .filter_by_name_unhygienic(method_name)
-                .next()
-                .is_some_and(|item| item.kind == ty::AssocKind::Fn)
-        })
+        cx.tcx
+            .inherent_impls(ty_did)
+            .into_iter()
+            .flatten()
+            .map(|&did| {
+                cx.tcx
+                    .associated_items(did)
+                    .filter_by_name_unhygienic(method_name)
+                    .next()
+                    .filter(|item| item.kind == ty::AssocKind::Fn)
+            })
+            .next()
+            .flatten()
     } else {
-        false
+        None
     }
 }
diff --git a/tests/ui/indexing_slicing_slice.rs b/tests/ui/indexing_slicing_slice.rs
index 721ba8facec..87a914db6fd 100644
--- a/tests/ui/indexing_slicing_slice.rs
+++ b/tests/ui/indexing_slicing_slice.rs
@@ -2,7 +2,13 @@
 // We also check the out_of_bounds_indexing lint here, because it lints similar things and
 // we want to avoid false positives.
 #![warn(clippy::out_of_bounds_indexing)]
-#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec)]
+#![allow(
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::useless_vec,
+    unused_must_use,
+    unused
+)]
 #![warn(clippy::indexing_slicing)]
 
 use std::ops::Index;
@@ -19,6 +25,28 @@ impl<T> Index<bool> for BoolMap<T> {
     }
 }
 
+struct BoolMapWithGet<T> {
+    false_value: T,
+    true_value: T,
+}
+
+impl<T> Index<bool> for BoolMapWithGet<T> {
+    type Output = T;
+    fn index(&self, index: bool) -> &Self::Output {
+        if index { &self.true_value } else { &self.false_value }
+    }
+}
+
+impl<T> BoolMapWithGet<T> {
+    fn get(&self, index: bool) -> Option<&T> {
+        if index {
+            Some(&self.true_value)
+        } else {
+            Some(&self.false_value)
+        }
+    }
+}
+
 fn main() {
     let x = [1, 2, 3, 4];
     let index: usize = 1;
@@ -73,4 +101,12 @@ fn main() {
     };
 
     map[true]; // Ok, because `get` does not exist (custom indexing)
+
+    let map_with_get = BoolMapWithGet {
+        false_value: 2,
+        true_value: 4,
+    };
+
+    // Lint on this, because `get` does exist with same signature
+    map_with_get[true];
 }