@@ -5,8 +5,8 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}
5
5
use rustc_ast as ast;
6
6
use rustc_errors:: Applicability ;
7
7
use rustc_hir:: def:: Res ;
8
- use rustc_hir:: { Expr , ExprKind , GenericArg , Path , PathSegment , QPath } ;
9
- use rustc_hir:: { HirId , Item , ItemKind , Node , Ty , TyKind } ;
8
+ use rustc_hir:: { Expr , ExprKind , GenericArg , PatKind , Path , PathSegment , QPath } ;
9
+ use rustc_hir:: { HirId , Item , ItemKind , Node , Pat , Ty , TyKind } ;
10
10
use rustc_middle:: ty;
11
11
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
12
12
use rustc_span:: hygiene:: { ExpnKind , MacroKind } ;
@@ -123,55 +123,115 @@ declare_lint_pass!(TyTyKind => [
123
123
] ) ;
124
124
125
125
impl < ' tcx > LateLintPass < ' tcx > for TyTyKind {
126
- fn check_path ( & mut self , cx : & LateContext < ' _ > , path : & ' tcx Path < ' tcx > , _: HirId ) {
127
- let segments = path. segments . iter ( ) . rev ( ) . skip ( 1 ) . rev ( ) ;
128
-
129
- if let Some ( last) = segments. last ( ) {
130
- let span = path. span . with_hi ( last. ident . span . hi ( ) ) ;
131
- if lint_ty_kind_usage ( cx, last) {
132
- cx. struct_span_lint ( USAGE_OF_TY_TYKIND , span, |lint| {
133
- lint. build ( "usage of `ty::TyKind::<kind>`" )
134
- . span_suggestion (
135
- span,
136
- "try using ty::<kind> directly" ,
137
- "ty" . to_string ( ) ,
138
- Applicability :: MaybeIncorrect , // ty maybe needs an import
139
- )
140
- . emit ( ) ;
141
- } )
142
- }
126
+ fn check_path (
127
+ & mut self ,
128
+ cx : & LateContext < ' tcx > ,
129
+ path : & ' tcx rustc_hir:: Path < ' tcx > ,
130
+ _: rustc_hir:: HirId ,
131
+ ) {
132
+ if let Some ( segment) = path. segments . iter ( ) . nth_back ( 1 )
133
+ && let Some ( res) = & segment. res
134
+ && lint_ty_kind_usage ( cx, res)
135
+ {
136
+ let span = path. span . with_hi (
137
+ segment. args . map_or ( segment. ident . span , |a| a. span_ext ) . hi ( )
138
+ ) ;
139
+ cx. struct_span_lint ( USAGE_OF_TY_TYKIND , path. span , |lint| {
140
+ lint. build ( "usage of `ty::TyKind::<kind>`" )
141
+ . span_suggestion (
142
+ span,
143
+ "try using `ty::<kind>` directly" ,
144
+ "ty" . to_string ( ) ,
145
+ Applicability :: MaybeIncorrect , // ty maybe needs an import
146
+ )
147
+ . emit ( ) ;
148
+ } ) ;
143
149
}
144
150
}
145
151
146
152
fn check_ty ( & mut self , cx : & LateContext < ' _ > , ty : & ' tcx Ty < ' tcx > ) {
147
153
match & ty. kind {
148
154
TyKind :: Path ( QPath :: Resolved ( _, path) ) => {
149
- if let Some ( last) = path. segments . iter ( ) . last ( ) {
150
- if lint_ty_kind_usage ( cx, last) {
151
- cx. struct_span_lint ( USAGE_OF_TY_TYKIND , path. span , |lint| {
152
- lint. build ( "usage of `ty::TyKind`" )
153
- . help ( "try using `Ty` instead" )
154
- . emit ( ) ;
155
- } )
156
- } else {
157
- if ty. span . from_expansion ( ) {
158
- return ;
159
- }
160
- if let Some ( t) = is_ty_or_ty_ctxt ( cx, ty) {
161
- if path. segments . len ( ) > 1 {
162
- cx. struct_span_lint ( USAGE_OF_QUALIFIED_TY , path. span , |lint| {
163
- lint. build ( & format ! ( "usage of qualified `ty::{}`" , t) )
155
+ if lint_ty_kind_usage ( cx, & path. res ) {
156
+ cx. struct_span_lint ( USAGE_OF_TY_TYKIND , path. span , |lint| {
157
+ let hir = cx. tcx . hir ( ) ;
158
+ match hir. find ( hir. get_parent_node ( ty. hir_id ) ) {
159
+ Some ( Node :: Pat ( Pat {
160
+ kind :
161
+ PatKind :: Path ( qpath)
162
+ | PatKind :: TupleStruct ( qpath, ..)
163
+ | PatKind :: Struct ( qpath, ..) ,
164
+ ..
165
+ } ) ) => {
166
+ if let QPath :: TypeRelative ( qpath_ty, ..) = qpath
167
+ && qpath_ty. hir_id == ty. hir_id
168
+ {
169
+ lint. build ( "usage of `ty::TyKind::<kind>`" )
170
+ . span_suggestion (
171
+ path. span ,
172
+ "try using `ty::<kind>` directly" ,
173
+ "ty" . to_string ( ) ,
174
+ Applicability :: MaybeIncorrect , // ty maybe needs an import
175
+ )
176
+ . emit ( ) ;
177
+ return ;
178
+ }
179
+ }
180
+ Some ( Node :: Expr ( Expr {
181
+ kind : ExprKind :: Path ( qpath) ,
182
+ ..
183
+ } ) ) => {
184
+ if let QPath :: TypeRelative ( qpath_ty, ..) = qpath
185
+ && qpath_ty. hir_id == ty. hir_id
186
+ {
187
+ lint. build ( "usage of `ty::TyKind::<kind>`" )
164
188
. span_suggestion (
165
189
path. span ,
166
- "try importing it and using it unqualified" ,
167
- t,
168
- // The import probably needs to be changed
169
- Applicability :: MaybeIncorrect ,
190
+ "try using `ty::<kind>` directly" ,
191
+ "ty" . to_string ( ) ,
192
+ Applicability :: MaybeIncorrect , // ty maybe needs an import
170
193
)
171
194
. emit ( ) ;
172
- } )
195
+ return ;
196
+ }
173
197
}
198
+ // Can't unify these two branches because qpath below is `&&` and above is `&`
199
+ // and `A | B` paths don't play well together with adjustments, apparently.
200
+ Some ( Node :: Expr ( Expr {
201
+ kind : ExprKind :: Struct ( qpath, ..) ,
202
+ ..
203
+ } ) ) => {
204
+ if let QPath :: TypeRelative ( qpath_ty, ..) = qpath
205
+ && qpath_ty. hir_id == ty. hir_id
206
+ {
207
+ lint. build ( "usage of `ty::TyKind::<kind>`" )
208
+ . span_suggestion (
209
+ path. span ,
210
+ "try using `ty::<kind>` directly" ,
211
+ "ty" . to_string ( ) ,
212
+ Applicability :: MaybeIncorrect , // ty maybe needs an import
213
+ )
214
+ . emit ( ) ;
215
+ return ;
216
+ }
217
+ }
218
+ _ => { }
174
219
}
220
+ lint. build ( "usage of `ty::TyKind`" ) . help ( "try using `Ty` instead" ) . emit ( ) ;
221
+ } )
222
+ } else if !ty. span . from_expansion ( ) && let Some ( t) = is_ty_or_ty_ctxt ( cx, & path) {
223
+ if path. segments . len ( ) > 1 {
224
+ cx. struct_span_lint ( USAGE_OF_QUALIFIED_TY , path. span , |lint| {
225
+ lint. build ( & format ! ( "usage of qualified `ty::{}`" , t) )
226
+ . span_suggestion (
227
+ path. span ,
228
+ "try importing it and using it unqualified" ,
229
+ t,
230
+ // The import probably needs to be changed
231
+ Applicability :: MaybeIncorrect ,
232
+ )
233
+ . emit ( ) ;
234
+ } )
175
235
}
176
236
}
177
237
}
@@ -180,42 +240,37 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
180
240
}
181
241
}
182
242
183
- fn lint_ty_kind_usage ( cx : & LateContext < ' _ > , segment : & PathSegment < ' _ > ) -> bool {
184
- if let Some ( res ) = segment . res {
185
- if let Some ( did) = res . opt_def_id ( ) {
186
- return cx . tcx . is_diagnostic_item ( sym :: TyKind , did ) ;
187
- }
243
+ fn lint_ty_kind_usage ( cx : & LateContext < ' _ > , res : & Res ) -> bool {
244
+ if let Some ( did ) = res. opt_def_id ( ) {
245
+ cx . tcx . is_diagnostic_item ( sym :: TyKind , did) || cx . tcx . is_diagnostic_item ( sym :: IrTyKind , did )
246
+ } else {
247
+ false
188
248
}
189
-
190
- false
191
249
}
192
250
193
- fn is_ty_or_ty_ctxt ( cx : & LateContext < ' _ > , ty : & Ty < ' _ > ) -> Option < String > {
194
- if let TyKind :: Path ( QPath :: Resolved ( _, path) ) = & ty. kind {
195
- match path. res {
196
- Res :: Def ( _, def_id) => {
197
- if let Some ( name @ ( sym:: Ty | sym:: TyCtxt ) ) = cx. tcx . get_diagnostic_name ( def_id) {
198
- return Some ( format ! ( "{}{}" , name, gen_args( path. segments. last( ) . unwrap( ) ) ) ) ;
199
- }
251
+ fn is_ty_or_ty_ctxt ( cx : & LateContext < ' _ > , path : & Path < ' _ > ) -> Option < String > {
252
+ match & path. res {
253
+ Res :: Def ( _, def_id) => {
254
+ if let Some ( name @ ( sym:: Ty | sym:: TyCtxt ) ) = cx. tcx . get_diagnostic_name ( * def_id) {
255
+ return Some ( format ! ( "{}{}" , name, gen_args( path. segments. last( ) . unwrap( ) ) ) ) ;
200
256
}
201
- // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
202
- Res :: SelfTy { trait_ : None , alias_to : Some ( ( did, _) ) } => {
203
- if let ty:: Adt ( adt, substs) = cx. tcx . type_of ( did) . kind ( ) {
204
- if let Some ( name @ ( sym:: Ty | sym:: TyCtxt ) ) =
205
- cx. tcx . get_diagnostic_name ( adt. did ( ) )
206
- {
207
- // NOTE: This path is currently unreachable as `Ty<'tcx>` is
208
- // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
209
- // is not actually allowed.
210
- //
211
- // I(@lcnr) still kept this branch in so we don't miss this
212
- // if we ever change it in the future.
213
- return Some ( format ! ( "{}<{}>" , name, substs[ 0 ] ) ) ;
214
- }
257
+ }
258
+ // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
259
+ Res :: SelfTy { trait_ : None , alias_to : Some ( ( did, _) ) } => {
260
+ if let ty:: Adt ( adt, substs) = cx. tcx . type_of ( did) . kind ( ) {
261
+ if let Some ( name @ ( sym:: Ty | sym:: TyCtxt ) ) = cx. tcx . get_diagnostic_name ( adt. did ( ) )
262
+ {
263
+ // NOTE: This path is currently unreachable as `Ty<'tcx>` is
264
+ // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
265
+ // is not actually allowed.
266
+ //
267
+ // I(@lcnr) still kept this branch in so we don't miss this
268
+ // if we ever change it in the future.
269
+ return Some ( format ! ( "{}<{}>" , name, substs[ 0 ] ) ) ;
215
270
}
216
271
}
217
- _ => ( ) ,
218
272
}
273
+ _ => ( ) ,
219
274
}
220
275
221
276
None
0 commit comments