From 88d425f32b3b49d5dfa8d86e6e4e2c263cd450d4 Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Tue, 11 Jun 2024 07:07:07 +0100 Subject: [PATCH] LibJS: Add the [[Unimplemented]] attribute Properties marked with the [[Unimplemented]] attribute behave as normal but invoke the `VM::on_unimplemented_property_access callback` when they are accessed. --- Userland/Libraries/LibJS/Runtime/Object.cpp | 7 +++++++ Userland/Libraries/LibJS/Runtime/PropertyAttributes.h | 3 +++ Userland/Libraries/LibJS/Runtime/PropertyDescriptor.h | 5 ++++- Userland/Libraries/LibJS/Runtime/VM.h | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibJS/Runtime/Object.cpp b/Userland/Libraries/LibJS/Runtime/Object.cpp index 406a3232181..d31829eba7c 100644 --- a/Userland/Libraries/LibJS/Runtime/Object.cpp +++ b/Userland/Libraries/LibJS/Runtime/Object.cpp @@ -808,6 +808,13 @@ ThrowCompletionOr> Object::internal_get_own_propert // 3. Let X be O's own property whose key is P. auto [value, attributes, property_offset] = *maybe_storage_entry; + // AD-HOC: Properties with the [[Unimplemented]] attribute are used for reporting unimplemented IDL interfaces. + if (attributes.is_unimplemented()) { + if (vm().on_unimplemented_property_access) + vm().on_unimplemented_property_access(*this, property_key); + descriptor.unimplemented = true; + } + // 4. If X is a data property, then if (!value.is_accessor()) { // a. Set D.[[Value]] to the value of X's [[Value]] attribute. diff --git a/Userland/Libraries/LibJS/Runtime/PropertyAttributes.h b/Userland/Libraries/LibJS/Runtime/PropertyAttributes.h index 1ab8a251fbc..fa15a21ba67 100644 --- a/Userland/Libraries/LibJS/Runtime/PropertyAttributes.h +++ b/Userland/Libraries/LibJS/Runtime/PropertyAttributes.h @@ -19,6 +19,8 @@ struct Attribute { Writable = 1 << 0, Enumerable = 1 << 1, Configurable = 1 << 2, + // AD-HOC: This is used for reporting unimplemented IDL interfaces. + Unimplemented = 1 << 3, }; }; @@ -33,6 +35,7 @@ public: [[nodiscard]] bool is_writable() const { return m_bits & Attribute::Writable; } [[nodiscard]] bool is_enumerable() const { return m_bits & Attribute::Enumerable; } [[nodiscard]] bool is_configurable() const { return m_bits & Attribute::Configurable; } + [[nodiscard]] bool is_unimplemented() const { return m_bits & Attribute::Unimplemented; } void set_writable(bool writable = true) { diff --git a/Userland/Libraries/LibJS/Runtime/PropertyDescriptor.h b/Userland/Libraries/LibJS/Runtime/PropertyDescriptor.h index d8888ce628f..9eea4de3154 100644 --- a/Userland/Libraries/LibJS/Runtime/PropertyDescriptor.h +++ b/Userland/Libraries/LibJS/Runtime/PropertyDescriptor.h @@ -31,7 +31,7 @@ public: // Not a standard abstract operation, but "If every field in Desc is absent". [[nodiscard]] bool is_empty() const { - return !value.has_value() && !get.has_value() && !set.has_value() && !writable.has_value() && !enumerable.has_value() && !configurable.has_value(); + return !value.has_value() && !get.has_value() && !set.has_value() && !writable.has_value() && !enumerable.has_value() && !configurable.has_value() && !unimplemented.has_value(); } Optional value {}; @@ -40,6 +40,7 @@ public: Optional writable {}; Optional enumerable {}; Optional configurable {}; + Optional unimplemented {}; Optional property_offset {}; }; @@ -65,6 +66,8 @@ struct Formatter : Formatter { TRY(parts.try_append(TRY(String::formatted("[[Enumerable]]: {}", *property_descriptor.enumerable)))); if (property_descriptor.configurable.has_value()) TRY(parts.try_append(TRY(String::formatted("[[Configurable]]: {}", *property_descriptor.configurable)))); + if (property_descriptor.unimplemented.has_value()) + TRY(parts.try_append(TRY(String::formatted("[[Unimplemented]]: {}", *property_descriptor.unimplemented)))); return Formatter::format(builder, TRY(String::formatted("PropertyDescriptor {{ {} }}", TRY(String::join(", "sv, parts))))); } }; diff --git a/Userland/Libraries/LibJS/Runtime/VM.h b/Userland/Libraries/LibJS/Runtime/VM.h index 80c247f559d..646c1eca3ed 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.h +++ b/Userland/Libraries/LibJS/Runtime/VM.h @@ -223,6 +223,7 @@ public: Function on_call_stack_emptied; Function on_promise_unhandled_rejection; Function on_promise_rejection_handled; + Function on_unimplemented_property_access; CustomData* custom_data() { return m_custom_data; }