diff --git a/Libraries/LibJS/Runtime/Object.h b/Libraries/LibJS/Runtime/Object.h index 6bd51041277..ebb40cb3102 100644 --- a/Libraries/LibJS/Runtime/Object.h +++ b/Libraries/LibJS/Runtime/Object.h @@ -111,6 +111,8 @@ public: virtual bool is_symbol_object() const { return false; } virtual bool is_bigint_object() const { return false; } + virtual bool is_web_wrapper() const { return false; } + virtual const char* class_name() const override { return "Object"; } virtual void visit_children(Cell::Visitor&) override; diff --git a/Libraries/LibWeb/Bindings/Wrapper.h b/Libraries/LibWeb/Bindings/Wrapper.h index 937385431f7..24c288b01c8 100644 --- a/Libraries/LibWeb/Bindings/Wrapper.h +++ b/Libraries/LibWeb/Bindings/Wrapper.h @@ -37,11 +37,17 @@ namespace Bindings { class Wrapper : public JS::Object , public Weakable { +public: + virtual bool is_node_wrapper() const { return false; } + virtual bool is_document_wrapper() const { return false; } + protected: explicit Wrapper(Object& prototype) : Object(&prototype) { } + + virtual bool is_web_wrapper() const final { return true; } }; } diff --git a/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp b/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp index eec1757eca3..9564a7a4ebf 100644 --- a/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp +++ b/Libraries/LibWeb/CodeGenerators/WrapperGenerator.cpp @@ -30,16 +30,19 @@ #include #include -static String snake_name(const StringView& camel_name) +static String snake_name(const StringView& title_name) { StringBuilder builder; - for (auto ch : camel_name) { + bool first = true; + for (auto ch : title_name) { if (isupper(ch)) { - builder.append('_'); + if (!first) + builder.append('_'); builder.append(tolower(ch)); } else { builder.append(ch); } + first = false; } return builder.to_string(); } @@ -338,6 +341,9 @@ static void generate_header(const IDL::Interface& interface) out() << " const " << interface.name << "& impl() const { return static_cast(" << wrapper_base_class << "::impl()); }"; } + auto is_foo_wrapper_name = snake_name(String::format("Is%s", wrapper_class.characters())); + out() << " virtual bool " << is_foo_wrapper_name << "() const final { return true; }"; + out() << "private:"; out() << " virtual const char* class_name() const override { return \"" << interface.name << "\"; }"; @@ -407,7 +413,8 @@ void generate_implementation(const IDL::Interface& interface) out() << " auto* this_object = interpreter.this_value(global_object).to_object(interpreter, global_object);"; out() << " if (!this_object)"; out() << " return {};"; - out() << " if (StringView(\"" << interface.name << "\") != this_object->class_name()) {"; + auto is_foo_wrapper_name = snake_name(String::format("Is%s", wrapper_class.characters())); + out() << " if (!this_object->is_web_wrapper() || !static_cast(this_object)->" << is_foo_wrapper_name << "()) {"; out() << " interpreter.throw_exception(JS::ErrorType::NotA, \"" << interface.name << "\");"; out() << " return nullptr;"; out() << " }";