11//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
22//! Clippy.
33
4- use crate :: hir:: { HirId , Path , PathSegment , QPath , Ty , TyKind } ;
4+ use crate :: hir:: { GenericArg , HirId , MutTy , Mutability , Path , PathSegment , QPath , Ty , TyKind } ;
55use crate :: lint:: {
66 EarlyContext , EarlyLintPass , LateContext , LateLintPass , LintArray , LintContext , LintPass ,
77} ;
@@ -57,12 +57,28 @@ impl EarlyLintPass for DefaultHashTypes {
5757declare_lint ! {
5858 pub USAGE_OF_TY_TYKIND ,
5959 Allow ,
60- "Usage of `ty::TyKind` outside of the `ty::sty` module"
60+ "usage of `ty::TyKind` outside of the `ty::sty` module"
6161}
6262
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+ ] ) ;
6480
65- impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for TyKindUsage {
81+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for TyTyKind {
6682 fn check_path ( & mut self , cx : & LateContext < ' _ , ' _ > , path : & ' tcx Path , _: HirId ) {
6783 let segments = path. segments . iter ( ) . rev ( ) . skip ( 1 ) . rev ( ) ;
6884
@@ -82,16 +98,72 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyKindUsage {
8298 }
8399
84100 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" )
91112 . 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 ;
92148 }
93149 }
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+ }
94165 }
166+ _ => { }
95167 }
96168 }
97169}
@@ -107,3 +179,43 @@ fn lint_ty_kind_usage(cx: &LateContext<'_, '_>, segment: &PathSegment) -> bool {
107179
108180 false
109181}
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