@@ -10,24 +10,31 @@ use rustc_typeck::hir_ty_to_ty;
10
10
use crate :: utils:: { match_type, paths, span_lint_and_help} ;
11
11
12
12
declare_clippy_lint ! {
13
- /// **What it does:**
13
+ /// **What it does:** Checks for maps with zero-sized value types anywhere in the code.
14
14
///
15
- /// **Why is this bad?**
15
+ /// **Why is this bad?** Since there is only a single value for a zero-sized type, a map
16
+ /// containing zero sized values is effectively a set. Using a set in that case improves
17
+ /// readability and communicates intent more clearly.
16
18
///
17
- /// **Known problems:** None.
19
+ /// **Known problems:** A zero-sized type cannot be recovered later if it contains private
20
+ /// fields.
18
21
///
19
22
/// **Example:**
20
23
///
21
24
/// ```rust
22
- /// // example code where clippy issues a warning
25
+ /// fn unique_words(text: &str) -> HashMap<&str, ()> {
26
+ /// todo!();
27
+ /// }
23
28
/// ```
24
29
/// Use instead:
25
30
/// ```rust
26
- /// // example code which does not raise clippy warning
31
+ /// fn unique_words(text: &str) -> HashSet<&str> {
32
+ /// todo!();
33
+ /// }
27
34
/// ```
28
35
pub ZERO_SIZED_MAP_VALUES ,
29
36
nursery,
30
- "default lint description "
37
+ "usage of map with zero-sized value type "
31
38
}
32
39
33
40
declare_lint_pass ! ( ZeroSizedMapValues => [ ZERO_SIZED_MAP_VALUES ] ) ;
@@ -59,7 +66,49 @@ impl ZeroSizedMapValues {
59
66
let ty = hir_ty_to_ty ( cx. tcx , hir_ty) ;
60
67
self . check_ty ( cx, ty, hir_ty. span ) ;
61
68
62
- // TODO recurse on qpath
69
+ match hir_ty. kind {
70
+ TyKind :: Path ( ref qpath) => match * qpath {
71
+ QPath :: Resolved ( ty, ref p) => {
72
+ if let Some ( ty) = ty {
73
+ self . check_hir_ty ( cx, ty) ;
74
+ }
75
+
76
+ for ty in p. segments . iter ( ) . flat_map ( |seg| {
77
+ seg. args
78
+ . as_ref ( )
79
+ . map_or_else ( || [ ] . iter ( ) , |params| params. args . iter ( ) )
80
+ . filter_map ( |arg| match arg {
81
+ GenericArg :: Type ( ty) => Some ( ty) ,
82
+ _ => None ,
83
+ } )
84
+ } ) {
85
+ self . check_hir_ty ( cx, ty) ;
86
+ }
87
+ } ,
88
+ QPath :: TypeRelative ( ty, ref seg) => {
89
+ self . check_hir_ty ( cx, ty) ;
90
+
91
+ if let Some ( ref params) = seg. args {
92
+ for ty in params. args . iter ( ) . filter_map ( |arg| match arg {
93
+ GenericArg :: Type ( ty) => Some ( ty) ,
94
+ _ => None ,
95
+ } ) {
96
+ self . check_hir_ty ( cx, ty) ;
97
+ }
98
+ }
99
+ } ,
100
+ QPath :: LangItem ( ..) => { } ,
101
+ } ,
102
+ TyKind :: Slice ( ref ty) | TyKind :: Array ( ref ty, _) | TyKind :: Ptr ( MutTy { ref ty, .. } ) => {
103
+ self . check_hir_ty ( cx, ty) ;
104
+ } ,
105
+ TyKind :: Tup ( tys) => {
106
+ for ty in tys {
107
+ self . check_hir_ty ( cx, ty) ;
108
+ }
109
+ } ,
110
+ _ => { } ,
111
+ }
63
112
}
64
113
65
114
fn check_ty < ' tcx > ( & mut self , cx : & LateContext < ' tcx > , ty : Ty < ' tcx > , span : Span ) {
0 commit comments