@@ -18,12 +18,13 @@ use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
18
18
use crate :: rustc:: { declare_tool_lint, lint_array} ;
19
19
use if_chain:: if_chain;
20
20
use crate :: rustc:: ty:: TyKind ;
21
+ use crate :: rustc:: ty:: FnSig ;
21
22
use crate :: rustc:: session:: config:: Config as SessionConfig ;
22
23
use crate :: rustc_target:: spec:: abi:: Abi ;
23
24
use crate :: rustc_target:: abi:: LayoutOf ;
24
25
use crate :: syntax:: ast:: NodeId ;
25
26
use crate :: syntax_pos:: Span ;
26
- use crate :: utils:: { in_macro, is_copy, is_self , span_lint_and_sugg, snippet} ;
27
+ use crate :: utils:: { in_macro, is_copy, is_self_ty , span_lint_and_sugg, snippet} ;
27
28
28
29
/// **What it does:** Checks for functions taking arguments by reference, where
29
30
/// the argument type is `Copy` and small enough to be more efficient to always
@@ -67,7 +68,7 @@ pub struct TriviallyCopyPassByRef {
67
68
limit : u64 ,
68
69
}
69
70
70
- impl TriviallyCopyPassByRef {
71
+ impl < ' a , ' tcx > TriviallyCopyPassByRef {
71
72
pub fn new ( limit : Option < u64 > , target : & SessionConfig ) -> Self {
72
73
let limit = limit. unwrap_or_else ( || {
73
74
let bit_width = target. usize_ty . bit_width ( ) . expect ( "usize should have a width" ) as u64 ;
@@ -80,6 +81,84 @@ impl TriviallyCopyPassByRef {
80
81
} ) ;
81
82
Self { limit }
82
83
}
84
+
85
+ fn check_trait_method (
86
+ & mut self ,
87
+ cx : & LateContext < ' _ , ' tcx > ,
88
+ item : & TraitItemRef
89
+ ) {
90
+ let method_def_id = cx. tcx . hir . local_def_id ( item. id . node_id ) ;
91
+ let method_sig = cx. tcx . fn_sig ( method_def_id) ;
92
+ let method_sig = cx. tcx . erase_late_bound_regions ( & method_sig) ;
93
+
94
+ let decl = match cx. tcx . hir . fn_decl ( item. id . node_id ) {
95
+ Some ( b) => b,
96
+ None => return ,
97
+ } ;
98
+
99
+ self . check_poly_fn ( cx, & decl, & method_sig, None ) ;
100
+ }
101
+
102
+ fn check_poly_fn (
103
+ & mut self ,
104
+ cx : & LateContext < ' _ , ' tcx > ,
105
+ decl : & FnDecl ,
106
+ sig : & FnSig < ' tcx > ,
107
+ span : Option < Span > ,
108
+ ) {
109
+ // Use lifetimes to determine if we're returning a reference to the
110
+ // argument. In that case we can't switch to pass-by-value as the
111
+ // argument will not live long enough.
112
+ let output_lts = match sig. output ( ) . sty {
113
+ TyKind :: Ref ( output_lt, _, _) => vec ! [ output_lt] ,
114
+ TyKind :: Adt ( _, substs) => substs. regions ( ) . collect ( ) ,
115
+ _ => vec ! [ ] ,
116
+ } ;
117
+
118
+ for ( input, & ty) in decl. inputs . iter ( ) . zip ( sig. inputs ( ) ) {
119
+ // All spans generated from a proc-macro invocation are the same...
120
+ match span {
121
+ Some ( s) if s == input. span => return ,
122
+ _ => ( ) ,
123
+ }
124
+
125
+ if_chain ! {
126
+ if let TyKind :: Ref ( input_lt, ty, Mutability :: MutImmutable ) = ty. sty;
127
+ if !output_lts. contains( & input_lt) ;
128
+ if is_copy( cx, ty) ;
129
+ if let Some ( size) = cx. layout_of( ty) . ok( ) . map( |l| l. size. bytes( ) ) ;
130
+ if size <= self . limit;
131
+ if let hir:: TyKind :: Rptr ( _, MutTy { ty: ref decl_ty, .. } ) = input. node;
132
+ then {
133
+ let value_type = if is_self_ty( decl_ty) {
134
+ "self" . into( )
135
+ } else {
136
+ snippet( cx, decl_ty. span, "_" ) . into( )
137
+ } ;
138
+ span_lint_and_sugg(
139
+ cx,
140
+ TRIVIALLY_COPY_PASS_BY_REF ,
141
+ input. span,
142
+ "this argument is passed by reference, but would be more efficient if passed by value" ,
143
+ "consider passing by value instead" ,
144
+ value_type) ;
145
+ }
146
+ }
147
+ }
148
+ }
149
+
150
+ fn check_trait_items (
151
+ & mut self ,
152
+ cx : & LateContext < ' _ , ' _ > ,
153
+ trait_items : & [ TraitItemRef ]
154
+ ) {
155
+ for item in trait_items {
156
+ match item. kind {
157
+ AssociatedItemKind :: Method { has_self : _ } => self . check_trait_method ( cx, item) ,
158
+ _ => ( ) ,
159
+ }
160
+ }
161
+ }
83
162
}
84
163
85
164
impl LintPass for TriviallyCopyPassByRef {
@@ -89,12 +168,22 @@ impl LintPass for TriviallyCopyPassByRef {
89
168
}
90
169
91
170
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for TriviallyCopyPassByRef {
171
+ fn check_item ( & mut self , cx : & LateContext < ' a , ' tcx > , item : & ' tcx Item ) {
172
+ if in_macro ( item. span ) {
173
+ return ;
174
+ }
175
+ match item. node {
176
+ ItemKind :: Trait ( _, _, _, _, ref trait_items) => self . check_trait_items ( cx, trait_items) ,
177
+ _ => ( ) ,
178
+ }
179
+ }
180
+
92
181
fn check_fn (
93
182
& mut self ,
94
183
cx : & LateContext < ' a , ' tcx > ,
95
184
kind : FnKind < ' tcx > ,
96
185
decl : & ' tcx FnDecl ,
97
- body : & ' tcx Body ,
186
+ _body : & ' tcx Body ,
98
187
span : Span ,
99
188
node_id : NodeId ,
100
189
) {
@@ -131,43 +220,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TriviallyCopyPassByRef {
131
220
let fn_sig = cx. tcx . fn_sig ( fn_def_id) ;
132
221
let fn_sig = cx. tcx . erase_late_bound_regions ( & fn_sig) ;
133
222
134
- // Use lifetimes to determine if we're returning a reference to the
135
- // argument. In that case we can't switch to pass-by-value as the
136
- // argument will not live long enough.
137
- let output_lts = match fn_sig. output ( ) . sty {
138
- TyKind :: Ref ( output_lt, _, _) => vec ! [ output_lt] ,
139
- TyKind :: Adt ( _, substs) => substs. regions ( ) . collect ( ) ,
140
- _ => vec ! [ ] ,
141
- } ;
142
-
143
- for ( ( input, & ty) , arg) in decl. inputs . iter ( ) . zip ( fn_sig. inputs ( ) ) . zip ( & body. arguments ) {
144
- // All spans generated from a proc-macro invocation are the same...
145
- if span == input. span {
146
- return ;
147
- }
148
-
149
- if_chain ! {
150
- if let TyKind :: Ref ( input_lt, ty, Mutability :: MutImmutable ) = ty. sty;
151
- if !output_lts. contains( & input_lt) ;
152
- if is_copy( cx, ty) ;
153
- if let Some ( size) = cx. layout_of( ty) . ok( ) . map( |l| l. size. bytes( ) ) ;
154
- if size <= self . limit;
155
- if let hir:: TyKind :: Rptr ( _, MutTy { ty: ref decl_ty, .. } ) = input. node;
156
- then {
157
- let value_type = if is_self( arg) {
158
- "self" . into( )
159
- } else {
160
- snippet( cx, decl_ty. span, "_" ) . into( )
161
- } ;
162
- span_lint_and_sugg(
163
- cx,
164
- TRIVIALLY_COPY_PASS_BY_REF ,
165
- input. span,
166
- "this argument is passed by reference, but would be more efficient if passed by value" ,
167
- "consider passing by value instead" ,
168
- value_type) ;
169
- }
170
- }
171
- }
223
+ self . check_poly_fn ( cx, decl, & fn_sig, Some ( span) ) ;
172
224
}
173
225
}
0 commit comments