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 rustc_hir:: HirId ;
5
4
use rustc_hir:: def:: Res ;
6
5
use rustc_hir:: def_id:: DefId ;
7
- use rustc_middle:: ty:: { self , GenericArgsRef , Ty as MiddleTy } ;
6
+ use rustc_hir:: { Expr , ExprKind , HirId } ;
7
+ use rustc_middle:: ty:: { self , ClauseKind , GenericArgsRef , PredicatePolarity , TraitPredicate , Ty } ;
8
8
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
9
9
use rustc_span:: hygiene:: { ExpnKind , MacroKind } ;
10
10
use rustc_span:: { Span , sym} ;
@@ -56,25 +56,6 @@ impl LateLintPass<'_> for DefaultHashTypes {
56
56
}
57
57
}
58
58
59
- /// Helper function for lints that check for expressions with calls and use typeck results to
60
- /// get the `DefId` and `GenericArgsRef` of the function.
61
- fn typeck_results_of_method_fn < ' tcx > (
62
- cx : & LateContext < ' tcx > ,
63
- expr : & hir:: Expr < ' _ > ,
64
- ) -> Option < ( Span , DefId , ty:: GenericArgsRef < ' tcx > ) > {
65
- match expr. kind {
66
- hir:: ExprKind :: MethodCall ( segment, ..)
67
- if let Some ( def_id) = cx. typeck_results ( ) . type_dependent_def_id ( expr. hir_id ) =>
68
- {
69
- Some ( ( segment. ident . span , def_id, cx. typeck_results ( ) . node_args ( expr. hir_id ) ) )
70
- }
71
- _ => match cx. typeck_results ( ) . node_type ( expr. hir_id ) . kind ( ) {
72
- & ty:: FnDef ( def_id, args) => Some ( ( expr. span , def_id, args) ) ,
73
- _ => None ,
74
- } ,
75
- }
76
- }
77
-
78
59
declare_tool_lint ! {
79
60
/// The `potential_query_instability` lint detects use of methods which can lead to
80
61
/// potential query instability, such as iterating over a `HashMap`.
@@ -101,10 +82,12 @@ declare_tool_lint! {
101
82
102
83
declare_lint_pass ! ( QueryStability => [ POTENTIAL_QUERY_INSTABILITY , UNTRACKED_QUERY_INFORMATION ] ) ;
103
84
104
- impl LateLintPass < ' _ > for QueryStability {
105
- fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > ) {
106
- let Some ( ( span, def_id, args) ) = typeck_results_of_method_fn ( cx, expr) else { return } ;
107
- if let Ok ( Some ( instance) ) = ty:: Instance :: try_resolve ( cx. tcx , cx. typing_env ( ) , def_id, args)
85
+ impl < ' tcx > LateLintPass < ' tcx > for QueryStability {
86
+ fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) {
87
+ if let Some ( ( callee_def_id, span, generic_args, _recv, _args) ) =
88
+ get_callee_span_generic_args_and_args ( cx, expr)
89
+ && let Ok ( Some ( instance) ) =
90
+ ty:: Instance :: try_resolve ( cx. tcx , cx. typing_env ( ) , callee_def_id, generic_args)
108
91
{
109
92
let def_id = instance. def_id ( ) ;
110
93
if cx. tcx . has_attr ( def_id, sym:: rustc_lint_query_instability) {
@@ -113,7 +96,15 @@ impl LateLintPass<'_> for QueryStability {
113
96
span,
114
97
QueryInstability { query : cx. tcx . item_name ( def_id) } ,
115
98
) ;
99
+ } else if has_unstable_into_iter_predicate ( cx, callee_def_id, generic_args) {
100
+ let call_span = span. with_hi ( expr. span . hi ( ) ) ;
101
+ cx. emit_span_lint (
102
+ POTENTIAL_QUERY_INSTABILITY ,
103
+ call_span,
104
+ QueryInstability { query : sym:: into_iter } ,
105
+ ) ;
116
106
}
107
+
117
108
if cx. tcx . has_attr ( def_id, sym:: rustc_lint_untracked_query_information) {
118
109
cx. emit_span_lint (
119
110
UNTRACKED_QUERY_INFORMATION ,
@@ -125,6 +116,64 @@ impl LateLintPass<'_> for QueryStability {
125
116
}
126
117
}
127
118
119
+ fn has_unstable_into_iter_predicate < ' tcx > (
120
+ cx : & LateContext < ' tcx > ,
121
+ callee_def_id : DefId ,
122
+ generic_args : GenericArgsRef < ' tcx > ,
123
+ ) -> bool {
124
+ let Some ( into_iterator_def_id) = cx. tcx . get_diagnostic_item ( sym:: IntoIterator ) else {
125
+ return false ;
126
+ } ;
127
+ let Some ( into_iter_fn_def_id) = cx. tcx . lang_items ( ) . into_iter_fn ( ) else {
128
+ return false ;
129
+ } ;
130
+ let predicates = cx. tcx . predicates_of ( callee_def_id) . instantiate ( cx. tcx , generic_args) ;
131
+ for ( predicate, _) in predicates {
132
+ let ClauseKind :: Trait ( TraitPredicate { trait_ref, polarity : PredicatePolarity :: Positive } ) =
133
+ predicate. kind ( ) . skip_binder ( )
134
+ else {
135
+ continue ;
136
+ } ;
137
+ // Does the function or method require any of its arguments to implement `IntoIterator`?
138
+ if trait_ref. def_id != into_iterator_def_id {
139
+ continue ;
140
+ }
141
+ let Ok ( Some ( instance) ) =
142
+ ty:: Instance :: try_resolve ( cx. tcx , cx. typing_env ( ) , into_iter_fn_def_id, trait_ref. args )
143
+ else {
144
+ continue ;
145
+ } ;
146
+ // Does the input type's `IntoIterator` implementation have the
147
+ // `rustc_lint_query_instability` attribute on its `into_iter` method?
148
+ if cx. tcx . has_attr ( instance. def_id ( ) , sym:: rustc_lint_query_instability) {
149
+ return true ;
150
+ }
151
+ }
152
+ false
153
+ }
154
+
155
+ /// Checks whether an expression is a function or method call and, if so, returns its `DefId`,
156
+ /// `Span`, `GenericArgs`, and arguments. This is a slight augmentation of a similarly named Clippy
157
+ /// function, `get_callee_generic_args_and_args`.
158
+ fn get_callee_span_generic_args_and_args < ' tcx > (
159
+ cx : & LateContext < ' tcx > ,
160
+ expr : & ' tcx Expr < ' tcx > ,
161
+ ) -> Option < ( DefId , Span , GenericArgsRef < ' tcx > , Option < & ' tcx Expr < ' tcx > > , & ' tcx [ Expr < ' tcx > ] ) > {
162
+ if let ExprKind :: Call ( callee, args) = expr. kind
163
+ && let callee_ty = cx. typeck_results ( ) . expr_ty ( callee)
164
+ && let ty:: FnDef ( callee_def_id, generic_args) = callee_ty. kind ( )
165
+ {
166
+ return Some ( ( * callee_def_id, callee. span , generic_args, None , args) ) ;
167
+ }
168
+ if let ExprKind :: MethodCall ( segment, recv, args, _) = expr. kind
169
+ && let Some ( method_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( expr. hir_id )
170
+ {
171
+ let generic_args = cx. typeck_results ( ) . node_args ( expr. hir_id ) ;
172
+ return Some ( ( method_def_id, segment. ident . span , generic_args, Some ( recv) , args) ) ;
173
+ }
174
+ None
175
+ }
176
+
128
177
declare_tool_lint ! {
129
178
/// The `usage_of_ty_tykind` lint detects usages of `ty::TyKind::<kind>`,
130
179
/// where `ty::<kind>` would suffice.
@@ -461,33 +510,22 @@ declare_tool_lint! {
461
510
declare_lint_pass ! ( Diagnostics => [ UNTRANSLATABLE_DIAGNOSTIC , DIAGNOSTIC_OUTSIDE_OF_IMPL ] ) ;
462
511
463
512
impl LateLintPass < ' _ > for Diagnostics {
464
- fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > ) {
513
+ fn check_expr < ' tcx > ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx hir:: Expr < ' tcx > ) {
465
514
let collect_args_tys_and_spans = |args : & [ hir:: Expr < ' _ > ] , reserve_one_extra : bool | {
466
515
let mut result = Vec :: with_capacity ( args. len ( ) + usize:: from ( reserve_one_extra) ) ;
467
516
result. extend ( args. iter ( ) . map ( |arg| ( cx. typeck_results ( ) . expr_ty ( arg) , arg. span ) ) ) ;
468
517
result
469
518
} ;
470
519
// Only check function calls and method calls.
471
- let ( span, def_id, fn_gen_args, arg_tys_and_spans) = match expr. kind {
472
- hir:: ExprKind :: Call ( callee, args) => {
473
- match cx. typeck_results ( ) . node_type ( callee. hir_id ) . kind ( ) {
474
- & ty:: FnDef ( def_id, fn_gen_args) => {
475
- ( callee. span , def_id, fn_gen_args, collect_args_tys_and_spans ( args, false ) )
476
- }
477
- _ => return , // occurs for fns passed as args
478
- }
479
- }
480
- hir:: ExprKind :: MethodCall ( _segment, _recv, args, _span) => {
481
- let Some ( ( span, def_id, fn_gen_args) ) = typeck_results_of_method_fn ( cx, expr)
482
- else {
483
- return ;
484
- } ;
485
- let mut args = collect_args_tys_and_spans ( args, true ) ;
486
- args. insert ( 0 , ( cx. tcx . types . self_param , _recv. span ) ) ; // dummy inserted for `self`
487
- ( span, def_id, fn_gen_args, args)
488
- }
489
- _ => return ,
520
+ let Some ( ( def_id, span, fn_gen_args, recv, args) ) =
521
+ get_callee_span_generic_args_and_args ( cx, expr)
522
+ else {
523
+ return ;
490
524
} ;
525
+ let mut arg_tys_and_spans = collect_args_tys_and_spans ( args, recv. is_some ( ) ) ;
526
+ if let Some ( recv) = recv {
527
+ arg_tys_and_spans. insert ( 0 , ( cx. tcx . types . self_param , recv. span ) ) ; // dummy inserted for `self`
528
+ }
491
529
492
530
Self :: diagnostic_outside_of_impl ( cx, span, expr. hir_id , def_id, fn_gen_args) ;
493
531
Self :: untranslatable_diagnostic ( cx, def_id, & arg_tys_and_spans) ;
@@ -496,7 +534,7 @@ impl LateLintPass<'_> for Diagnostics {
496
534
497
535
impl Diagnostics {
498
536
// Is the type `{D,Subd}iagMessage`?
499
- fn is_diag_message < ' cx > ( cx : & LateContext < ' cx > , ty : MiddleTy < ' cx > ) -> bool {
537
+ fn is_diag_message < ' cx > ( cx : & LateContext < ' cx > , ty : Ty < ' cx > ) -> bool {
500
538
if let Some ( adt_def) = ty. ty_adt_def ( )
501
539
&& let Some ( name) = cx. tcx . get_diagnostic_name ( adt_def. did ( ) )
502
540
&& matches ! ( name, sym:: DiagMessage | sym:: SubdiagMessage )
@@ -510,7 +548,7 @@ impl Diagnostics {
510
548
fn untranslatable_diagnostic < ' cx > (
511
549
cx : & LateContext < ' cx > ,
512
550
def_id : DefId ,
513
- arg_tys_and_spans : & [ ( MiddleTy < ' cx > , Span ) ] ,
551
+ arg_tys_and_spans : & [ ( Ty < ' cx > , Span ) ] ,
514
552
) {
515
553
let fn_sig = cx. tcx . fn_sig ( def_id) . instantiate_identity ( ) . skip_binder ( ) ;
516
554
let predicates = cx. tcx . predicates_of ( def_id) . instantiate_identity ( cx. tcx ) . predicates ;
0 commit comments