| 3758 | } |
| 3759 | |
| 3760 | bool ObjectPrototype::hook_up_vfunc_impl(JSContext* cx, |
| 3761 | const JS::CallArgs& args) { |
| 3762 | JS::UniqueChars name; |
| 3763 | JS::RootedObject callable(cx); |
| 3764 | bool is_static = false; |
| 3765 | if (!gjs_parse_call_args(cx, "hook_up_vfunc", args, "so|b", "name", &name, |
| 3766 | "function", &callable, "is_static", &is_static)) |
| 3767 | return false; |
| 3768 | |
| 3769 | args.rval().setUndefined(); |
| 3770 | |
| 3771 | // find the first class that actually has repository information |
| 3772 | GI::Repository repo; |
| 3773 | Maybe<GI::AutoObjectInfo> info = m_info; |
| 3774 | GType info_gtype = m_gtype; |
| 3775 | while (!info && info_gtype != G_TYPE_OBJECT) { |
| 3776 | info_gtype = g_type_parent(info_gtype); |
| 3777 | |
| 3778 | info = repo.find_by_gtype<GI::InfoTag::OBJECT>(info_gtype); |
| 3779 | } |
| 3780 | |
| 3781 | /* If we don't have 'info', we don't have the base class (GObject). This is |
| 3782 | * awful, so abort now. */ |
| 3783 | g_assert(info); |
| 3784 | |
| 3785 | Maybe<GI::AutoVFuncInfo> vfunc{info->vfunc(name.get())}; |
| 3786 | // Search the parent type chain |
| 3787 | while (!vfunc && info_gtype != G_TYPE_OBJECT) { |
| 3788 | info_gtype = g_type_parent(info_gtype); |
| 3789 | |
| 3790 | info = repo.find_by_gtype<GI::InfoTag::OBJECT>(info_gtype); |
| 3791 | if (info) |
| 3792 | vfunc = info->vfunc(name.get()); |
| 3793 | } |
| 3794 | |
| 3795 | // If the vfunc doesn't exist in the parent type chain, loop through the |
| 3796 | // explicitly defined interfaces... |
| 3797 | if (!vfunc) { |
| 3798 | for (GType interface_gtype : m_interface_gtypes) { |
| 3799 | Maybe<GI::AutoInterfaceInfo> interface{ |
| 3800 | repo.find_by_gtype<GI::InfoTag::INTERFACE>(interface_gtype)}; |
| 3801 | |
| 3802 | // Private and dynamic interfaces (defined in JS) do not have type |
| 3803 | // info. |
| 3804 | if (interface) { |
| 3805 | vfunc = interface->vfunc(name.get()); |
| 3806 | if (vfunc) |
| 3807 | break; |
| 3808 | } |
| 3809 | } |
| 3810 | } |
| 3811 | |
| 3812 | // If the vfunc is still not found, it could exist on an interface |
| 3813 | // implemented by a parent. This is an error, as hooking up the vfunc would |
| 3814 | // create an implementation on the interface itself. In this case, print a |
| 3815 | // more helpful error than "Could not find definition of virtual function" |
| 3816 | // |
| 3817 | // See https://gitlab.gnome.org/GNOME/gjs/-/issues/89 |
no test coverage detected