33
33
34
34
use metadata:: { csearch, decoder} ;
35
35
use middle:: { cfg, def, infer, pat_util, stability, traits} ;
36
- use middle:: def:: * ;
37
36
use middle:: subst:: Substs ;
38
37
use middle:: ty:: { self , Ty } ;
39
38
use middle:: const_eval:: { eval_const_expr_partial, ConstVal } ;
@@ -2251,34 +2250,73 @@ impl LintPass for UnconditionalRecursion {
2251
2250
}
2252
2251
}
2253
2252
2254
- // Check if the method call `id` refers to method `method`.
2253
+ // Check if the expression `id` performs a call to `method`.
2255
2254
fn expr_refers_to_this_method ( tcx : & ty:: ctxt ,
2256
2255
method : & ty:: Method ,
2257
2256
id : ast:: NodeId ) -> bool {
2258
- let method_call = ty:: MethodCall :: expr ( id) ;
2259
- let callee = match tcx. tables . borrow ( ) . method_map . get ( & method_call) {
2260
- Some ( & m) => m,
2261
- None => return false
2262
- } ;
2263
- let callee_item = tcx. impl_or_trait_item ( callee. def_id ) ;
2257
+ let tables = tcx. tables . borrow ( ) ;
2258
+
2259
+ // Check for method calls and overloaded operators.
2260
+ if let Some ( m) = tables. method_map . get ( & ty:: MethodCall :: expr ( id) ) {
2261
+ if method_call_refers_to_method ( tcx, method, m. def_id , m. substs , id) {
2262
+ return true ;
2263
+ }
2264
+ }
2265
+
2266
+ // Check for overloaded autoderef method calls.
2267
+ if let Some ( & ty:: AdjustDerefRef ( ref adj) ) = tables. adjustments . get ( & id) {
2268
+ for i in 0 ..adj. autoderefs {
2269
+ let method_call = ty:: MethodCall :: autoderef ( id, i as u32 ) ;
2270
+ if let Some ( m) = tables. method_map . get ( & method_call) {
2271
+ if method_call_refers_to_method ( tcx, method, m. def_id , m. substs , id) {
2272
+ return true ;
2273
+ }
2274
+ }
2275
+ }
2276
+ }
2277
+
2278
+ // Check for calls to methods via explicit paths (e.g. `T::method()`).
2279
+ match tcx. map . get ( id) {
2280
+ ast_map:: NodeExpr ( & ast:: Expr { node : ast:: ExprCall ( ref callee, _) , .. } ) => {
2281
+ match tcx. def_map . borrow ( ) . get ( & callee. id ) . map ( |d| d. full_def ( ) ) {
2282
+ Some ( def:: DefMethod ( def_id) ) => {
2283
+ let no_substs = & ty:: ItemSubsts :: empty ( ) ;
2284
+ let ts = tables. item_substs . get ( & callee. id ) . unwrap_or ( no_substs) ;
2285
+ method_call_refers_to_method ( tcx, method, def_id, & ts. substs , id)
2286
+ }
2287
+ _ => false
2288
+ }
2289
+ }
2290
+ _ => false
2291
+ }
2292
+ }
2293
+
2294
+ // Check if the method call to the method with the ID `callee_id`
2295
+ // and instantiated with `callee_substs` refers to method `method`.
2296
+ fn method_call_refers_to_method < ' tcx > ( tcx : & ty:: ctxt < ' tcx > ,
2297
+ method : & ty:: Method ,
2298
+ callee_id : ast:: DefId ,
2299
+ callee_substs : & Substs < ' tcx > ,
2300
+ expr_id : ast:: NodeId ) -> bool {
2301
+ let callee_item = tcx. impl_or_trait_item ( callee_id) ;
2264
2302
2265
2303
match callee_item. container ( ) {
2266
2304
// This is an inherent method, so the `def_id` refers
2267
2305
// directly to the method definition.
2268
2306
ty:: ImplContainer ( _) => {
2269
- callee . def_id == method. def_id
2307
+ callee_id == method. def_id
2270
2308
}
2271
2309
2272
2310
// A trait method, from any number of possible sources.
2273
2311
// Attempt to select a concrete impl before checking.
2274
2312
ty:: TraitContainer ( trait_def_id) => {
2275
- let trait_substs = callee . substs . clone ( ) . method_to_trait ( ) ;
2313
+ let trait_substs = callee_substs . clone ( ) . method_to_trait ( ) ;
2276
2314
let trait_substs = tcx. mk_substs ( trait_substs) ;
2277
2315
let trait_ref = ty:: TraitRef :: new ( trait_def_id, trait_substs) ;
2278
2316
let trait_ref = ty:: Binder ( trait_ref) ;
2279
- let span = tcx. map . span ( id ) ;
2317
+ let span = tcx. map . span ( expr_id ) ;
2280
2318
let obligation =
2281
- traits:: Obligation :: new ( traits:: ObligationCause :: misc ( span, id ) ,
2319
+ traits:: Obligation :: new ( traits:: ObligationCause :: misc ( span, expr_id ) ,
2282
2320
trait_ref. to_poly_trait_predicate ( ) ) ;
2283
2321
2284
2322
let param_env = ty:: ParameterEnvironment :: for_item ( tcx, method. def_id . node ) ;
@@ -2289,12 +2327,12 @@ impl LintPass for UnconditionalRecursion {
2289
2327
// If `T` is `Self`, then this call is inside
2290
2328
// a default method definition.
2291
2329
Ok ( Some ( traits:: VtableParam ( _) ) ) => {
2292
- let self_ty = callee . substs . self_ty ( ) ;
2330
+ let self_ty = callee_substs . self_ty ( ) ;
2293
2331
let on_self = self_ty. map_or ( false , |t| t. is_self ( ) ) ;
2294
2332
// We can only be recurring in a default
2295
2333
// method if we're being called literally
2296
2334
// on the `Self` type.
2297
- on_self && callee . def_id == method. def_id
2335
+ on_self && callee_id == method. def_id
2298
2336
}
2299
2337
2300
2338
// The `impl` is known, so we check that with a
@@ -2454,7 +2492,7 @@ impl LintPass for MutableTransmutes {
2454
2492
ast:: ExprPath ( ..) => ( ) ,
2455
2493
_ => return None
2456
2494
}
2457
- if let DefFn ( did, _) = cx. tcx . resolve_expr ( expr) {
2495
+ if let def :: DefFn ( did, _) = cx. tcx . resolve_expr ( expr) {
2458
2496
if !def_id_is_transmute ( cx, did) {
2459
2497
return None ;
2460
2498
}
0 commit comments