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 } ;
22use rustc_errors:: Applicability ;
33use rustc_hir as hir;
44use rustc_lint:: LateContext ;
55
66use super :: UNNECESSARY_LITERAL_UNWRAP ;
77
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+
824pub ( super ) fn check (
925 cx : & LateContext < ' _ > ,
1026 expr : & hir:: Expr < ' _ > ,
@@ -14,59 +30,66 @@ pub(super) fn check(
1430) {
1531 let init = clippy_utils:: expr_or_init ( cx, recv) ;
1632
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 ) )
2445 } else {
2546 return ;
2647 }
2748 } else if is_res_lang_ctor ( cx, path_res ( cx, init) , hir:: LangItem :: OptionNone ) {
2849 let call_args: & [ hir:: Expr < ' _ > ] = & [ ] ;
29- ( "None" , call_args)
50+ ( "None" , call_args, None )
3051 } else {
3152 return ;
3253 } ;
3354
3455 let help_message = format ! ( "used `{method}()` on `{constructor}` value" ) ;
3556 let suggestion_message = format ! ( "remove the `{constructor}` and `{method}()`" ) ;
3657
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+ } ;
6485
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+ } ) ;
7295}
0 commit comments