1
1
//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
2
2
//! Clippy.
3
3
4
- use crate :: hir:: { HirId , Path , PathSegment , QPath , Ty , TyKind } ;
4
+ use crate :: hir:: { GenericArg , HirId , MutTy , Mutability , Path , PathSegment , QPath , Ty , TyKind } ;
5
5
use crate :: lint:: {
6
6
EarlyContext , EarlyLintPass , LateContext , LateLintPass , LintArray , LintContext , LintPass ,
7
7
} ;
@@ -57,12 +57,28 @@ impl EarlyLintPass for DefaultHashTypes {
57
57
declare_lint ! {
58
58
pub USAGE_OF_TY_TYKIND ,
59
59
Allow ,
60
- "Usage of `ty::TyKind` outside of the `ty::sty` module"
60
+ "usage of `ty::TyKind` outside of the `ty::sty` module"
61
61
}
62
62
63
- declare_lint_pass ! ( TyKindUsage => [ USAGE_OF_TY_TYKIND ] ) ;
63
+ declare_lint ! {
64
+ pub TY_PASS_BY_REFERENCE ,
65
+ Allow ,
66
+ "passing `Ty` or `TyCtxt` by reference"
67
+ }
68
+
69
+ declare_lint ! {
70
+ pub USAGE_OF_QUALIFIED_TY ,
71
+ Allow ,
72
+ "using `ty::{Ty,TyCtxt}` instead of importing it"
73
+ }
74
+
75
+ declare_lint_pass ! ( TyTyKind => [
76
+ USAGE_OF_TY_TYKIND ,
77
+ TY_PASS_BY_REFERENCE ,
78
+ USAGE_OF_QUALIFIED_TY ,
79
+ ] ) ;
64
80
65
- impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for TyKindUsage {
81
+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for TyTyKind {
66
82
fn check_path ( & mut self , cx : & LateContext < ' _ , ' _ > , path : & ' tcx Path , _: HirId ) {
67
83
let segments = path. segments . iter ( ) . rev ( ) . skip ( 1 ) . rev ( ) ;
68
84
@@ -82,16 +98,72 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyKindUsage {
82
98
}
83
99
84
100
fn check_ty ( & mut self , cx : & LateContext < ' _ , ' _ > , ty : & ' tcx Ty ) {
85
- if let TyKind :: Path ( qpath) = & ty. node {
86
- if let QPath :: Resolved ( _, path) = qpath {
87
- if let Some ( last) = path. segments . iter ( ) . last ( ) {
88
- if lint_ty_kind_usage ( cx, last) {
89
- cx. struct_span_lint ( USAGE_OF_TY_TYKIND , path. span , "usage of `ty::TyKind`" )
90
- . help ( "try using `ty::Ty` instead" )
101
+ match & ty. node {
102
+ TyKind :: Path ( qpath) => {
103
+ if let QPath :: Resolved ( _, path) = qpath {
104
+ if let Some ( last) = path. segments . iter ( ) . last ( ) {
105
+ if lint_ty_kind_usage ( cx, last) {
106
+ cx. struct_span_lint (
107
+ USAGE_OF_TY_TYKIND ,
108
+ path. span ,
109
+ "usage of `ty::TyKind`" ,
110
+ )
111
+ . help ( "try using `Ty` instead" )
91
112
. emit ( ) ;
113
+ } else {
114
+ if ty. span . ctxt ( ) . outer ( ) . expn_info ( ) . is_some ( ) {
115
+ return ;
116
+ }
117
+ if let Some ( t) = is_ty_or_ty_ctxt ( cx, ty) {
118
+ if path. segments . len ( ) > 1 {
119
+ cx. struct_span_lint (
120
+ USAGE_OF_QUALIFIED_TY ,
121
+ path. span ,
122
+ & format ! ( "usage of qualified `ty::{}`" , t) ,
123
+ )
124
+ . span_suggestion (
125
+ path. span ,
126
+ "try using it unqualified" ,
127
+ t,
128
+ // The import probably needs to be changed
129
+ Applicability :: MaybeIncorrect ,
130
+ )
131
+ . emit ( ) ;
132
+ }
133
+ }
134
+ }
135
+ }
136
+ }
137
+ }
138
+ TyKind :: Rptr (
139
+ _,
140
+ MutTy {
141
+ ty : inner_ty,
142
+ mutbl : Mutability :: MutImmutable ,
143
+ } ,
144
+ ) => {
145
+ if let Some ( impl_did) = cx. tcx . impl_of_method ( ty. hir_id . owner_def_id ( ) ) {
146
+ if cx. tcx . impl_trait_ref ( impl_did) . is_some ( ) {
147
+ return ;
92
148
}
93
149
}
150
+ if let Some ( t) = is_ty_or_ty_ctxt ( cx, & inner_ty) {
151
+ cx. struct_span_lint (
152
+ TY_PASS_BY_REFERENCE ,
153
+ ty. span ,
154
+ & format ! ( "passing `{}` by reference" , t) ,
155
+ )
156
+ . span_suggestion (
157
+ ty. span ,
158
+ "try passing by value" ,
159
+ t,
160
+ // Changing type of function argument
161
+ Applicability :: MaybeIncorrect ,
162
+ )
163
+ . emit ( ) ;
164
+ }
94
165
}
166
+ _ => { }
95
167
}
96
168
}
97
169
}
@@ -107,3 +179,43 @@ fn lint_ty_kind_usage(cx: &LateContext<'_, '_>, segment: &PathSegment) -> bool {
107
179
108
180
false
109
181
}
182
+
183
+ fn is_ty_or_ty_ctxt ( cx : & LateContext < ' _ , ' _ > , ty : & Ty ) -> Option < String > {
184
+ match & ty. node {
185
+ TyKind :: Path ( qpath) => {
186
+ if let QPath :: Resolved ( _, path) = qpath {
187
+ let did = path. def . opt_def_id ( ) ?;
188
+ if cx. match_def_path ( did, & [ "rustc" , "ty" , "Ty" ] ) {
189
+ return Some ( format ! ( "Ty{}" , gen_args( path. segments. last( ) . unwrap( ) ) ) ) ;
190
+ } else if cx. match_def_path ( did, & [ "rustc" , "ty" , "context" , "TyCtxt" ] ) {
191
+ return Some ( format ! ( "TyCtxt{}" , gen_args( path. segments. last( ) . unwrap( ) ) ) ) ;
192
+ }
193
+ }
194
+ }
195
+ _ => { }
196
+ }
197
+
198
+ None
199
+ }
200
+
201
+ fn gen_args ( segment : & PathSegment ) -> String {
202
+ if let Some ( args) = & segment. args {
203
+ let lifetimes = args
204
+ . args
205
+ . iter ( )
206
+ . filter_map ( |arg| {
207
+ if let GenericArg :: Lifetime ( lt) = arg {
208
+ Some ( lt. name . ident ( ) . to_string ( ) )
209
+ } else {
210
+ None
211
+ }
212
+ } )
213
+ . collect :: < Vec < _ > > ( ) ;
214
+
215
+ if !lifetimes. is_empty ( ) {
216
+ return format ! ( "<{}>" , lifetimes. join( ", " ) ) ;
217
+ }
218
+ }
219
+
220
+ String :: new ( )
221
+ }
0 commit comments