avm2: Refactor `Object.delete_property` to work similar to get/set

This commit is contained in:
David Wendt 2021-11-04 20:18:59 -04:00 committed by kmeisthax
parent e67ca1afe0
commit 503dc08594
5 changed files with 62 additions and 30 deletions

View File

@ -1405,19 +1405,9 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
(multiname, object) (multiname, object)
}; };
if let Some(name) = object.resolve_multiname(&multiname)? {
self.context self.context
.avm2 .avm2
.push(object.delete_property(self.context.gc_context, &name)) .push(object.delete_property(self.context.gc_context, &multiname)?);
} else {
// Unknown properties on a dynamic class delete successfully.
self.context.avm2.push(
!object
.instance_of_class_definition()
.map(|c| c.read().is_sealed())
.unwrap_or(false),
)
}
Ok(FrameControl::Continue) Ok(FrameControl::Continue)
} }

View File

@ -672,37 +672,67 @@ pub trait TObject<'gc>: 'gc + Collect + Debug + Into<Object<'gc>> + Clone + Copy
base.is_property_overwritable(name) base.is_property_overwritable(name)
} }
/// Delete a property by QName, after multiname resolution and all other
/// considerations have been taken.
///
/// This required method is only intended to be called by other TObject
/// methods.
fn delete_property_local(
&self,
gc_context: MutationContext<'gc, '_>,
name: &QName<'gc>,
) -> Result<bool, Error> {
let mut base = self.base_mut(gc_context);
Ok(base.delete_property(name))
}
/// Delete a named property from the object. /// Delete a named property from the object.
/// ///
/// Returns false if the property cannot be deleted. /// Returns false if the property cannot be deleted.
fn delete_property(&self, gc_context: MutationContext<'gc, '_>, name: &QName<'gc>) -> bool { fn delete_property(
let mut base = self.base_mut(gc_context); &self,
gc_context: MutationContext<'gc, '_>,
multiname: &Multiname<'gc>,
) -> Result<bool, Error> {
let name = self.resolve_multiname(multiname)?;
if name.is_none() {
// Unknown properties on a dynamic class delete successfully.
return Ok(!self
.instance_of_class_definition()
.map(|c| c.read().is_sealed())
.unwrap_or(false));
}
//At this point, the name should be known.
let name = name.unwrap();
// Reject attempts to delete lazy-bound methods before they have // Reject attempts to delete lazy-bound methods before they have
// been bound. // been bound.
if !base.has_own_instantiated_property(name) { if !self.base().has_own_instantiated_property(&name) {
if let Some(class) = self.instance_of() { if let Some(class) = self.instance_of() {
if class if class
.instance_method(name) .instance_method(&name)
.map(|t| t.is_some()) .map(|t| t.is_some())
.unwrap_or(false) .unwrap_or(false)
{ {
return false; return Ok(false);
} }
} }
if let Some(class) = self.as_class_object() { if let Some(class) = self.as_class_object() {
if class if class
.class_method(name) .class_method(&name)
.map(|t| t.is_some()) .map(|t| t.is_some())
.unwrap_or(false) .unwrap_or(false)
{ {
return false; return Ok(false);
} }
} }
} }
base.delete_property(name) self.delete_property_local(gc_context, &name)
} }
/// Retrieve the `__proto__` of a given object. /// Retrieve the `__proto__` of a given object.

View File

@ -164,15 +164,19 @@ impl<'gc> TObject<'gc> for ArrayObject<'gc> {
Ok(()) Ok(())
} }
fn delete_property(&self, gc_context: MutationContext<'gc, '_>, name: &QName<'gc>) -> bool { fn delete_property_local(
&self,
gc_context: MutationContext<'gc, '_>,
name: &QName<'gc>,
) -> Result<bool, Error> {
if name.namespace().is_public() { if name.namespace().is_public() {
if let Ok(index) = name.local_name().parse::<usize>() { if let Ok(index) = name.local_name().parse::<usize>() {
self.0.write(gc_context).array.delete(index); self.0.write(gc_context).array.delete(index);
return true; return Ok(true);
} }
} }
self.0.write(gc_context).base.delete_property(name) Ok(self.0.write(gc_context).base.delete_property(name))
} }
fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error> { fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error> {

View File

@ -163,15 +163,19 @@ impl<'gc> TObject<'gc> for ByteArrayObject<'gc> {
Ok(()) Ok(())
} }
fn delete_property(&self, gc_context: MutationContext<'gc, '_>, name: &QName<'gc>) -> bool { fn delete_property_local(
&self,
gc_context: MutationContext<'gc, '_>,
name: &QName<'gc>,
) -> Result<bool, Error> {
if name.namespace().is_public() { if name.namespace().is_public() {
if let Ok(index) = name.local_name().parse::<usize>() { if let Ok(index) = name.local_name().parse::<usize>() {
self.0.write(gc_context).storage.delete(index); self.0.write(gc_context).storage.delete(index);
return true; return Ok(true);
} }
} }
self.0.write(gc_context).base.delete_property(name) Ok(self.0.write(gc_context).base.delete_property(name))
} }
fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error> { fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error> {

View File

@ -195,12 +195,16 @@ impl<'gc> TObject<'gc> for VectorObject<'gc> {
Ok(()) Ok(())
} }
fn delete_property(&self, gc_context: MutationContext<'gc, '_>, name: &QName<'gc>) -> bool { fn delete_property_local(
&self,
gc_context: MutationContext<'gc, '_>,
name: &QName<'gc>,
) -> Result<bool, Error> {
if name.namespace().is_package("") && name.local_name().parse::<usize>().is_ok() { if name.namespace().is_package("") && name.local_name().parse::<usize>().is_ok() {
return true; return Ok(true);
} }
self.0.write(gc_context).base.delete_property(name) Ok(self.0.write(gc_context).base.delete_property(name))
} }
fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error> { fn has_own_property(self, name: &QName<'gc>) -> Result<bool, Error> {