@@ -5,8 +5,8 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}
55use rustc_ast as ast;
66use rustc_errors:: Applicability ;
77use 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 } ;
1010use rustc_middle:: ty;
1111use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
1212use rustc_span:: hygiene:: { ExpnKind , MacroKind } ;
@@ -123,55 +123,115 @@ declare_lint_pass!(TyTyKind => [
123123] ) ;
124124
125125impl < ' 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+ } ) ;
143149 }
144150 }
145151
146152 fn check_ty ( & mut self , cx : & LateContext < ' _ > , ty : & ' tcx Ty < ' tcx > ) {
147153 match & ty. kind {
148154 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>`" )
164188 . span_suggestion (
165189 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
170193 )
171194 . emit ( ) ;
172- } )
195+ return ;
196+ }
173197 }
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+ _ => { }
174219 }
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+ } )
175235 }
176236 }
177237 }
@@ -180,42 +240,37 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
180240 }
181241}
182242
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
188248 }
189-
190- false
191249}
192250
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( ) ) ) ) ;
200256 }
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 ] ) ) ;
215270 }
216271 }
217- _ => ( ) ,
218272 }
273+ _ => ( ) ,
219274 }
220275
221276 None
0 commit comments