|
1 | 1 | use if_chain::if_chain;
|
2 |
| -use rustc_hir::{self as hir, intravisit::FnKind, *}; |
| 2 | +use rustc_hir::{self as hir, *}; |
3 | 3 | use rustc_lint::{LateContext, LateLintPass};
|
4 | 4 | use rustc_middle::ty::{Adt, Ty};
|
5 | 5 | use rustc_session::{declare_lint_pass, declare_tool_lint};
|
6 |
| -use rustc_span::Span; |
7 | 6 | use rustc_target::abi::LayoutOf as _;
|
8 | 7 | use rustc_typeck::hir_ty_to_ty;
|
9 | 8 |
|
10 |
| -use crate::utils::{match_type, paths, span_lint_and_help}; |
| 9 | +use crate::utils::{is_type_diagnostic_item, match_type, paths, span_lint_and_help}; |
11 | 10 |
|
12 | 11 | declare_clippy_lint! {
|
13 | 12 | /// **What it does:** Checks for maps with zero-sized value types anywhere in the code.
|
@@ -41,41 +40,41 @@ declare_clippy_lint! {
|
41 | 40 | declare_lint_pass!(ZeroSizedMapValues => [ZERO_SIZED_MAP_VALUES]);
|
42 | 41 |
|
43 | 42 | impl LateLintPass<'_> for ZeroSizedMapValues {
|
44 |
| - fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { |
45 |
| - let ty = cx.typeck_results().pat_ty(local.pat); |
46 |
| - |
47 |
| - self.check_ty(cx, ty, local.pat.span); |
48 |
| - } |
49 |
| - |
50 | 43 | fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
|
51 |
| - let parent_id = cx.tcx.hir().get_parent_item(hir_ty.hir_id); |
52 |
| - if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_item(parent_id)) { |
53 |
| - if let ItemKind::Impl { of_trait: Some(_), .. } = item.kind { |
54 |
| - return; |
55 |
| - } |
56 |
| - } |
57 |
| - |
58 |
| - // TODO this causes errors in some cases |
59 |
| - let ty = hir_ty_to_ty(cx.tcx, hir_ty); |
60 |
| - self.check_ty(cx, ty, hir_ty.span); |
61 |
| - } |
62 |
| -} |
63 |
| - |
64 |
| -impl ZeroSizedMapValues { |
65 |
| - fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) { |
66 |
| - if span.from_expansion() { |
67 |
| - return; |
68 |
| - } |
69 |
| - |
70 | 44 | if_chain! {
|
71 |
| - if match_type(cx, ty, &paths::HASHMAP) || match_type(cx, ty, &paths::BTREEMAP); |
| 45 | + if !hir_ty.span.from_expansion(); |
| 46 | + if !in_trait_impl(cx, hir_ty.hir_id); |
| 47 | + let ty = ty_from_hir_ty(cx, hir_ty); |
| 48 | + if is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) || match_type(cx, ty, &paths::BTREEMAP); |
72 | 49 | if let Adt(_, ref substs) = ty.kind();
|
73 | 50 | let ty = substs.type_at(1);
|
74 | 51 | if let Ok(layout) = cx.layout_of(ty);
|
75 | 52 | if layout.is_zst();
|
76 | 53 | then {
|
77 |
| - span_lint_and_help(cx, ZERO_SIZED_MAP_VALUES, span, "map with zero-sized value type", None, "consider using a set instead"); |
| 54 | + span_lint_and_help(cx, ZERO_SIZED_MAP_VALUES, hir_ty.span, "map with zero-sized value type", None, "consider using a set instead"); |
78 | 55 | }
|
79 | 56 | }
|
80 | 57 | }
|
81 | 58 | }
|
| 59 | + |
| 60 | +fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool { |
| 61 | + let parent_id = cx.tcx.hir().get_parent_item(hir_id); |
| 62 | + if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_item(parent_id)) { |
| 63 | + if let ItemKind::Impl { of_trait: Some(_), .. } = item.kind { |
| 64 | + return true; |
| 65 | + } |
| 66 | + } |
| 67 | + false |
| 68 | +} |
| 69 | + |
| 70 | +fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { |
| 71 | + cx.maybe_typeck_results() |
| 72 | + .and_then(|results| { |
| 73 | + if results.hir_owner == hir_ty.hir_id.owner { |
| 74 | + results.node_type_opt(hir_ty.hir_id) |
| 75 | + } else { |
| 76 | + None |
| 77 | + } |
| 78 | + }) |
| 79 | + .unwrap_or_else(|| hir_ty_to_ty(cx.tcx, hir_ty)) |
| 80 | +} |
0 commit comments