@@ -9,15 +9,15 @@ extern crate rustc_middle;
9
9
extern crate rustc_span;
10
10
11
11
use clippy_utils:: {
12
- diagnostics:: span_lint_and_help, get_trait_def_id, match_def_path, ty:: implements_trait,
12
+ diagnostics:: span_lint_and_help, get_trait_def_id, match_def_path, ty:: { match_type , implements_trait} ,
13
13
} ;
14
14
use rustc_data_structures:: fx:: FxHashMap ;
15
15
use rustc_hir:: { def:: Res , Expr , ExprKind , QPath , TyKind } ;
16
16
use rustc_index:: vec:: Idx ;
17
17
use rustc_lint:: { LateContext , LateLintPass } ;
18
18
use rustc_middle:: ty:: { AdtDef , AdtKind , TyKind as MiddleTyKind } ;
19
19
use rustc_span:: { def_id:: DefId , Span } ;
20
- use solana_lints:: paths;
20
+ use solana_lints:: { paths, utils :: visit_expr_no_bodies } ;
21
21
22
22
use if_chain:: if_chain;
23
23
@@ -74,51 +74,48 @@ impl<'tcx> LateLintPass<'tcx> for TypeCosplay {
74
74
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) {
75
75
if_chain ! {
76
76
if !expr. span. from_expansion( ) ;
77
- if let ExprKind :: Call ( fnc_expr, _args_exprs) = expr. kind;
78
- // TODO: is the following if statement really needed?? don't think it's ever used.
79
- // all it does is check if AccountInfo.data is referenced...but what bytes we deser
80
- // from shouldn't impact if this is a type-cosplay issue or not.
81
- // walk each argument expression and see if the data field is referenced
82
- // TODO: maybe just check arg is a byte array
83
- // if args_exprs.iter().any(|arg| {
84
- // visit_expr_no_bodies(arg, |expr| contains_data_field_reference(cx, expr))
85
- // });
77
+ if let ExprKind :: Call ( fnc_expr, args_exprs) = expr. kind;
78
+ // TODO: recommended case will exit early since it contains a reference to AccountInfo.data,
79
+ // not a direct argument. In general, any references will fail
80
+ if args_exprs. iter( ) . any( |arg| {
81
+ visit_expr_no_bodies( arg, |expr| contains_data_field_reference( cx, expr) )
82
+ } ) ;
86
83
// get the type that the function was called on, ie X in X::call()
87
84
if let ExprKind :: Path ( qpath) = & fnc_expr. kind;
88
85
if let QPath :: TypeRelative ( ty, _) = qpath;
89
86
if let TyKind :: Path ( ty_qpath) = & ty. kind;
90
87
let res = cx. typeck_results( ) . qpath_res( ty_qpath, ty. hir_id) ;
91
88
if let Res :: Def ( _, def_id) = res;
92
89
let middle_ty = cx. tcx. type_of( def_id) ;
93
- if let Some ( trait_did) = get_trait_def_id( cx, & paths:: ANCHOR_DISCRIMINATOR_TRAIT ) ;
94
90
then {
95
- if implements_trait( cx, middle_ty, trait_did, & [ ] ) {
96
- if let Some ( def_id) = cx. typeck_results( ) . type_dependent_def_id( fnc_expr. hir_id)
97
- {
98
- if !match_def_path( cx, def_id, & paths:: ANCHOR_TRY_DESERIALIZE ) {
99
- span_lint_and_help(
100
- cx,
101
- TYPE_COSPLAY ,
102
- fnc_expr. span,
103
- & format!( "`{}` type implements the `Discriminator` trait. If you are attempting to deserialize\n here and `{}` is annotated with #[account] use try_deserialize() instead." ,
104
- middle_ty,
105
- middle_ty
106
- ) ,
107
- None ,
108
- "otherwise, make sure you are accounting for this type's discriminator in your deserialization function"
109
- ) ;
110
- }
111
- }
112
- } else {
113
- // currently only checks borsh::try_from_slice()
114
- if is_deserialize_function( cx, fnc_expr) {
115
- if let MiddleTyKind :: Adt ( adt_def, _) = middle_ty. kind( ) {
116
- let adt_kind = adt_def. adt_kind( ) ;
117
- let def_id = adt_def. did( ) ;
118
- if let Some ( vec) = self . deser_types. get_mut( & adt_kind) {
119
- vec. push( ( def_id, ty. span) ) ;
120
- } else {
121
- self . deser_types. insert( adt_kind, vec![ ( def_id, ty. span) ] ) ;
91
+ if_chain! {
92
+ if let Some ( trait_did) = get_trait_def_id( cx, & paths:: ANCHOR_DISCRIMINATOR_TRAIT ) ;
93
+ if implements_trait( cx, middle_ty, trait_did, & [ ] ) ;
94
+ if let Some ( def_id) = cx. typeck_results( ) . type_dependent_def_id( fnc_expr. hir_id) ;
95
+ if !match_def_path( cx, def_id, & paths:: ANCHOR_TRY_DESERIALIZE ) ;
96
+ then {
97
+ span_lint_and_help(
98
+ cx,
99
+ TYPE_COSPLAY ,
100
+ fnc_expr. span,
101
+ & format!( "`{}` type implements the `Discriminator` trait. If you are attempting to deserialize\n here and `{}` is annotated with #[account] use try_deserialize() instead." ,
102
+ middle_ty,
103
+ middle_ty
104
+ ) ,
105
+ None ,
106
+ "otherwise, make sure you are accounting for this type's discriminator in your deserialization function"
107
+ ) ;
108
+ } else {
109
+ // currently only checks borsh::try_from_slice()
110
+ if is_deserialize_function( cx, fnc_expr) {
111
+ if let MiddleTyKind :: Adt ( adt_def, _) = middle_ty. kind( ) {
112
+ let adt_kind = adt_def. adt_kind( ) ;
113
+ let def_id = adt_def. did( ) ;
114
+ if let Some ( vec) = self . deser_types. get_mut( & adt_kind) {
115
+ vec. push( ( def_id, ty. span) ) ;
116
+ } else {
117
+ self . deser_types. insert( adt_kind, vec![ ( def_id, ty. span) ] ) ;
118
+ }
122
119
}
123
120
}
124
121
}
@@ -161,19 +158,19 @@ fn is_deserialize_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
161
158
}
162
159
}
163
160
164
- // fn contains_data_field_reference(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
165
- // if_chain! {
166
- // if let ExprKind::Field(obj_expr, ident) = expr.kind;
167
- // if ident.as_str() == "data";
168
- // let ty = cx.typeck_results().expr_ty(obj_expr);
169
- // if match_type(cx, ty, &paths::SOLANA_PROGRAM_ACCOUNT_INFO);
170
- // then {
171
- // true
172
- // } else {
173
- // false
174
- // }
175
- // }
176
- // }
161
+ fn contains_data_field_reference ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> bool {
162
+ if_chain ! {
163
+ if let ExprKind :: Field ( obj_expr, ident) = expr. kind;
164
+ if ident. as_str( ) == "data" ;
165
+ let ty = cx. typeck_results( ) . expr_ty( obj_expr) ;
166
+ if match_type( cx, ty, & paths:: SOLANA_PROGRAM_ACCOUNT_INFO ) ;
167
+ then {
168
+ true
169
+ } else {
170
+ false
171
+ }
172
+ }
173
+ }
177
174
178
175
fn check_enums ( cx : & LateContext < ' _ > , enums : & Vec < ( DefId , Span ) > ) {
179
176
#[ allow( clippy:: comparison_chain) ]
0 commit comments