1
- use clippy_utils:: { diagnostics:: span_lint_and_then, is_res_lang_ctor, path_res} ;
1
+ use clippy_utils:: { diagnostics:: span_lint_and_then, is_res_lang_ctor, last_path_segment , path_res, MaybePath } ;
2
2
use rustc_errors:: Applicability ;
3
3
use rustc_hir as hir;
4
4
use rustc_lint:: LateContext ;
5
5
6
6
use super :: UNNECESSARY_LITERAL_UNWRAP ;
7
7
8
+ fn get_ty_from_args < ' a > ( args : Option < & ' a [ hir:: GenericArg < ' a > ] > , index : usize ) -> Option < & ' a hir:: Ty < ' a > > {
9
+ let args = args?;
10
+
11
+ if args. len ( ) <= index {
12
+ return None ;
13
+ }
14
+
15
+ match args[ index] {
16
+ hir:: GenericArg :: Type ( ty) => match ty. kind {
17
+ hir:: TyKind :: Infer => None ,
18
+ _ => Some ( ty) ,
19
+ } ,
20
+ _ => None ,
21
+ }
22
+ }
23
+
8
24
pub ( super ) fn check (
9
25
cx : & LateContext < ' _ > ,
10
26
expr : & hir:: Expr < ' _ > ,
@@ -14,59 +30,66 @@ pub(super) fn check(
14
30
) {
15
31
let init = clippy_utils:: expr_or_init ( cx, recv) ;
16
32
17
- let ( constructor, call_args) = if let hir:: ExprKind :: Call ( call, call_args) = init. kind {
18
- if is_res_lang_ctor ( cx, path_res ( cx, call) , hir:: LangItem :: OptionSome ) {
19
- ( "Some" , call_args)
20
- } else if is_res_lang_ctor ( cx, path_res ( cx, call) , hir:: LangItem :: ResultOk ) {
21
- ( "Ok" , call_args)
22
- } else if is_res_lang_ctor ( cx, path_res ( cx, call) , hir:: LangItem :: ResultErr ) {
23
- ( "Err" , call_args)
33
+ let ( constructor, call_args, ty) = if let hir:: ExprKind :: Call ( call, call_args) = init. kind {
34
+ let Some ( qpath) = call. qpath_opt ( ) else { return } ;
35
+
36
+ let args = last_path_segment ( qpath) . args . map ( |args| args. args ) ;
37
+ let res = cx. qpath_res ( qpath, call. hir_id ( ) ) ;
38
+
39
+ if is_res_lang_ctor ( cx, res, hir:: LangItem :: OptionSome ) {
40
+ ( "Some" , call_args, get_ty_from_args ( args, 0 ) )
41
+ } else if is_res_lang_ctor ( cx, res, hir:: LangItem :: ResultOk ) {
42
+ ( "Ok" , call_args, get_ty_from_args ( args, 0 ) )
43
+ } else if is_res_lang_ctor ( cx, res, hir:: LangItem :: ResultErr ) {
44
+ ( "Err" , call_args, get_ty_from_args ( args, 1 ) )
24
45
} else {
25
46
return ;
26
47
}
27
48
} else if is_res_lang_ctor ( cx, path_res ( cx, init) , hir:: LangItem :: OptionNone ) {
28
49
let call_args: & [ hir:: Expr < ' _ > ] = & [ ] ;
29
- ( "None" , call_args)
50
+ ( "None" , call_args, None )
30
51
} else {
31
52
return ;
32
53
} ;
33
54
34
55
let help_message = format ! ( "used `{method}()` on `{constructor}` value" ) ;
35
56
let suggestion_message = format ! ( "remove the `{constructor}` and `{method}()`" ) ;
36
57
37
- if init . span == recv . span {
38
- span_lint_and_then ( cx , UNNECESSARY_LITERAL_UNWRAP , expr . span , & help_message , |diag| {
39
- let suggestions = match ( constructor , method ) {
40
- ( "None" , "unwrap" ) => vec ! [ ( expr . span , "panic!()" . to_string ( ) ) ] ,
41
- ( "None" , "expect" ) => vec ! [
42
- ( expr. span. with_hi ( args[ 0 ] . span. lo ( ) ) , "panic!( " . to_string( ) ) ,
43
- ( expr . span . with_lo ( args [ 0 ] . span . hi ( ) ) , ")" . to_string ( ) ) ,
44
- ] ,
45
- ( "Ok" , "unwrap_err" ) | ( "Err" , "unwrap" ) => vec ! [
46
- (
47
- recv. span. with_hi( call_args[ 0 ] . span. lo( ) ) ,
48
- "panic!(\" {:?}\" , " . to_string( ) ,
49
- ) ,
50
- ( expr. span. with_lo( call_args[ 0 ] . span. hi( ) ) , ")" . to_string( ) ) ,
51
- ] ,
52
- ( "Ok" , "expect_err" ) | ( "Err" , "expect" ) => vec ! [
53
- (
54
- recv. span. with_hi( call_args[ 0 ] . span. lo( ) ) ,
55
- "panic!(\" {1}: {:?}\" , " . to_string( ) ,
56
- ) ,
57
- ( call_args[ 0 ] . span. with_lo( args[ 0 ] . span. lo( ) ) , ", " . to_string( ) ) ,
58
- ] ,
59
- _ => vec ! [
60
- ( recv. span. with_hi( call_args[ 0 ] . span. lo( ) ) , String :: new( ) ) ,
61
- ( expr. span. with_lo( call_args[ 0 ] . span. hi( ) ) , String :: new( ) ) ,
62
- ] ,
63
- } ;
58
+ span_lint_and_then ( cx , UNNECESSARY_LITERAL_UNWRAP , expr . span , & help_message , |diag| {
59
+ let suggestions = match ( constructor , method , ty ) {
60
+ ( "None" , "unwrap" , _ ) => Some ( vec ! [ ( expr . span , "panic!()" . to_string ( ) ) ] ) ,
61
+ ( "None" , "expect" , _ ) => Some ( vec ! [
62
+ ( expr . span . with_hi ( args [ 0 ] . span . lo ( ) ) , "panic!(" . to_string ( ) ) ,
63
+ ( expr. span. with_lo ( args[ 0 ] . span. hi ( ) ) , ") " . to_string( ) ) ,
64
+ ] ) ,
65
+ ( _ , _ , Some ( _ ) ) => None ,
66
+ ( "Ok" , "unwrap_err" , None ) | ( "Err" , "unwrap" , None ) => Some ( vec ! [
67
+ (
68
+ recv. span. with_hi( call_args[ 0 ] . span. lo( ) ) ,
69
+ "panic!(\" {:?}\" , " . to_string( ) ,
70
+ ) ,
71
+ ( expr. span. with_lo( call_args[ 0 ] . span. hi( ) ) , ")" . to_string( ) ) ,
72
+ ] ) ,
73
+ ( "Ok" , "expect_err" , None ) | ( "Err" , "expect" , None ) => Some ( vec ! [
74
+ (
75
+ recv. span. with_hi( call_args[ 0 ] . span. lo( ) ) ,
76
+ "panic!(\" {1}: {:?}\" , " . to_string( ) ,
77
+ ) ,
78
+ ( call_args[ 0 ] . span. with_lo( args[ 0 ] . span. lo( ) ) , ", " . to_string( ) ) ,
79
+ ] ) ,
80
+ ( _ , _ , None ) => Some ( vec ! [
81
+ ( recv. span. with_hi( call_args[ 0 ] . span. lo( ) ) , String :: new( ) ) ,
82
+ ( expr. span. with_lo( call_args[ 0 ] . span. hi( ) ) , String :: new( ) ) ,
83
+ ] ) ,
84
+ } ;
64
85
65
- diag. multipart_suggestion ( suggestion_message, suggestions, Applicability :: MachineApplicable ) ;
66
- } ) ;
67
- } else {
68
- span_lint_and_then ( cx, UNNECESSARY_LITERAL_UNWRAP , expr. span , & help_message, |diag| {
69
- diag. span_help ( init. span , suggestion_message) ;
70
- } ) ;
71
- }
86
+ match ( init. span == recv. span , suggestions) {
87
+ ( true , Some ( suggestions) ) => {
88
+ diag. multipart_suggestion ( suggestion_message, suggestions, Applicability :: MachineApplicable ) ;
89
+ } ,
90
+ _ => {
91
+ diag. span_help ( init. span , suggestion_message) ;
92
+ } ,
93
+ }
94
+ } ) ;
72
95
}
0 commit comments