Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(lint): Support index operations (vec[])
  • Loading branch information
jubnzv committed Oct 3, 2023
commit 1de2f21b602000bee7b7d217582c80078bebecf3
83 changes: 57 additions & 26 deletions linting/src/storage_never_freed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,39 +243,70 @@ impl<'a, 'b, 'tcx> InsertRemoveCollector<'a, 'b, 'tcx> {
fn new(cx: &'tcx LateContext<'a>, fields: &'b mut FieldsMap) -> Self {
Self { cx, fields }
}

/// Finds a field of the supported type in the given expression present with the form
/// `self.field_name`
fn find_field_name(&self, e: &Expr) -> Option<String> {
if_chain! {
if let ExprKind::Field(s, field) = &e.kind;
if let ExprKind::Path(ref path) = s.kind;
let ty = self.cx.qpath_res(path, s.hir_id);
// TODO: check if ty is `self`
then { Some(field.name.as_str().to_string()) } else { None }
}
}
}

impl<'hir> Visitor<'hir> for InsertRemoveCollector<'_, '_, '_> {
fn visit_expr(&mut self, e: &'hir Expr<'hir>) {
if let ExprKind::MethodCall(method_path, receiver, args, _) = &e.kind {
if_chain! {
if let ExprKind::Field(s, field) = &receiver.kind;
if let ExprKind::Path(ref path) = s.kind;
let ty = self.cx.qpath_res(path, s.hir_id);
// TODO: check if self
let field_name = field.name.as_str();
let method_name = method_path.ident.as_str();
then {
self.fields.entry(field_name.to_string()).and_modify(|field_info| {
match field_info.ty {
CollectionTy::Vec if VEC_INSERT_OPERATIONS.contains(&method_name) => {
field_info.has_insert = true;
},
CollectionTy::Vec if VEC_REMOVE_OPERATIONS.contains(&method_name) => {
field_info.has_remove = true;
},
CollectionTy::Map if MAP_INSERT_OPERATIONS.contains(&method_name) => {
match &e.kind {
ExprKind::Assign(lhs, ..) => {
if_chain! {
if let ExprKind::Index(field, _) = lhs.kind;
if let Some(field_name) = self.find_field_name(field);
then {
self.fields
.entry(field_name.to_string())
.and_modify(|field_info| {
field_info.has_insert = true;
},
CollectionTy::Map if MAP_REMOVE_OPERATIONS.contains(&method_name) => {
field_info.has_remove = true;
},
_ => ()
}
});
});
}
}
}
ExprKind::MethodCall(method_path, receiver, args, _) => {
if let Some(field_name) = self.find_field_name(receiver) {
let method_name = method_path.ident.as_str();
self.fields
.entry(field_name.to_string())
.and_modify(|field_info| {
match field_info.ty {
CollectionTy::Vec
if VEC_INSERT_OPERATIONS.contains(&method_name) =>
{
field_info.has_insert = true;
}
CollectionTy::Vec
if VEC_REMOVE_OPERATIONS.contains(&method_name) =>
{
field_info.has_remove = true;
}
CollectionTy::Map
if MAP_INSERT_OPERATIONS.contains(&method_name) =>
{
field_info.has_insert = true;
}
CollectionTy::Map
if MAP_REMOVE_OPERATIONS.contains(&method_name) =>
{
field_info.has_remove = true;
}
_ => (),
}
});
}
args.iter().for_each(|arg| walk_expr(self, arg));
}
args.iter().for_each(|arg| walk_expr(self, arg));
_ => (),
}
walk_expr(self, e);
}
Expand Down
9 changes: 6 additions & 3 deletions linting/ui/fail/storage_never_freed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,28 @@ pub mod storage_never_freed {
// All the fields generate warnings, since there are `insert` operations for
// them, but there are no `remove` operations.
vec_field: Vec<AccountId>,
vec_field_subscription: Vec<AccountId>,
map_field: Mapping<AccountId, AccountId>,
map_field2: MapAlias2<AccountId, AccountId>,
map_field_alias: MapAlias2<AccountId, AccountId>,
}

impl StorageNeverFreed {
#[ink(constructor)]
pub fn new() -> Self {
Self {
vec_field: Vec::new(),
vec_field_subscription: Vec::new(),
map_field: Mapping::new(),
map_field2: Mapping::new(),
map_field_alias: Mapping::new(),
}
}

#[ink(message)]
pub fn add_to_fields(&mut self, v: AccountId) {
self.vec_field.push(v);
self.map_field.insert(v, &v);
self.map_field2.insert(v, &v);
self.vec_field_subscription[0] = v;
self.map_field_alias.insert(v, &v);
}
}
}
Expand Down