Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
For now we ignore not-yet-defined interfaces in the runtimeclass (and coclass) interface list, but it's probably worth emitting a warning at least, after Wine uses have been cleaned - which will take a while.
tools/widl/parser.l | 1 + tools/widl/parser.y | 16 +++++++++++++--- tools/widl/typetree.c | 34 +++++++++++++++++++++++++++++++++- tools/widl/typetree.h | 9 ++++++++- tools/widl/widltypes.h | 1 + 5 files changed, 56 insertions(+), 5 deletions(-)
diff --git a/tools/widl/parser.l b/tools/widl/parser.l index 9b93a53b839..946dba84cd6 100644 --- a/tools/widl/parser.l +++ b/tools/widl/parser.l @@ -298,6 +298,7 @@ static const struct keyword keywords[] = { {"pascal", tPASCAL, 0}, {"properties", tPROPERTIES, 0}, {"register", tREGISTER, 0}, + {"requires", tREQUIRES, 1}, {"runtimeclass", tRUNTIMECLASS, 1}, {"short", tSHORT, 0}, {"signed", tSIGNED, 0}, diff --git a/tools/widl/parser.y b/tools/widl/parser.y index b8c916f8336..a6128074f2d 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -240,6 +240,7 @@ static typelib_t *current_typelib; %token tREADONLY tREF %token tREGISTER tREPRESENTAS %token tREQUESTEDIT +%token tREQUIRES %token tRESTRICTED %token tRETVAL %token tRUNTIMECLASS @@ -293,6 +294,7 @@ static typelib_t *current_typelib; %type <type> type unqualified_type qualified_type %type <ifref> class_interface %type <ifref_list> class_interfaces +%type <ifref_list> requires required_types %type <var> arg ne_union_field union_field s_field case enum enum_member declaration %type <var> funcdef %type <var_list> m_args arg_list args dispint_meths @@ -967,8 +969,16 @@ inherit: { $$ = NULL; } interface: tINTERFACE typename { $$ = type_interface_declare($2, current_namespace); } ;
-interfacedef: attributes interface inherit - '{' int_statements '}' semicolon_opt { $$ = type_interface_define($2, $1, $3, $5); +required_types: + qualified_type { $$ = append_ifref(NULL, make_ifref($1)); } + | required_types ',' qualified_type { $$ = append_ifref($1, make_ifref($3)); } + +requires: { $$ = NULL; } + | tREQUIRES required_types { $$ = $2; } + ; + +interfacedef: attributes interface inherit requires + '{' int_statements '}' semicolon_opt { $$ = type_interface_define($2, $1, $3, $6, $4); check_async_uuid($$); } | dispinterfacedef semicolon_opt { $$ = $1; } @@ -2981,7 +2991,7 @@ static void check_async_uuid(type_t *iface) stmts = append_statement(stmts, make_statement_declaration(finish_func)); }
- type_interface_define(async_iface, map_attrs(iface->attrs, async_iface_attrs), inherit, stmts); + type_interface_define(async_iface, map_attrs(iface->attrs, async_iface_attrs), inherit, stmts, NULL); iface->details.iface->async_iface = async_iface->details.iface->async_iface = async_iface; }
diff --git a/tools/widl/typetree.c b/tools/widl/typetree.c index b3f0725f00e..3c2f183eb13 100644 --- a/tools/widl/typetree.c +++ b/tools/widl/typetree.c @@ -441,7 +441,7 @@ type_t *type_interface_declare(char *name, struct namespace *namespace) return type; }
-type_t *type_interface_define(type_t *iface, attr_list_t *attrs, type_t *inherit, statement_list_t *stmts) +type_t *type_interface_define(type_t *iface, attr_list_t *attrs, type_t *inherit, statement_list_t *stmts, ifref_list_t *requires) { if (iface->defined) error_loc("interface %s already defined at %s:%d\n", @@ -457,6 +457,7 @@ type_t *type_interface_define(type_t *iface, attr_list_t *attrs, type_t *inherit iface->details.iface->inherit = inherit; iface->details.iface->disp_inherit = NULL; iface->details.iface->async_iface = NULL; + iface->details.iface->requires = requires; iface->defined = TRUE; compute_method_indexes(iface); return iface; @@ -485,6 +486,7 @@ type_t *type_dispinterface_define(type_t *iface, attr_list_t *attrs, var_list_t if (!iface->details.iface->inherit) error_loc("IDispatch is undefined\n"); iface->details.iface->disp_inherit = NULL; iface->details.iface->async_iface = NULL; + iface->details.iface->requires = NULL; iface->defined = TRUE; compute_method_indexes(iface); return iface; @@ -504,6 +506,7 @@ type_t *type_dispinterface_define_from_iface(type_t *dispiface, attr_list_t *att if (!dispiface->details.iface->inherit) error_loc("IDispatch is undefined\n"); dispiface->details.iface->disp_inherit = iface; dispiface->details.iface->async_iface = NULL; + dispiface->details.iface->requires = NULL; dispiface->defined = TRUE; compute_method_indexes(dispiface); return dispiface; @@ -561,6 +564,9 @@ type_t *type_runtimeclass_declare(char *name, struct namespace *namespace)
type_t *type_runtimeclass_define(type_t *runtimeclass, attr_list_t *attrs, ifref_list_t *ifaces) { + ifref_t *ifref, *required, *tmp; + ifref_list_t *requires; + if (runtimeclass->defined) error_loc("runtimeclass %s already defined at %s:%d\n", runtimeclass->name, runtimeclass->loc_info.input_name, runtimeclass->loc_info.line_number); @@ -569,6 +575,28 @@ type_t *type_runtimeclass_define(type_t *runtimeclass, attr_list_t *attrs, ifref runtimeclass->defined = TRUE; if (!type_runtimeclass_get_default_iface(runtimeclass)) error_loc("missing default interface on runtimeclass %s\n", runtimeclass->name); + + LIST_FOR_EACH_ENTRY(ifref, ifaces, ifref_t, entry) + { + /* FIXME: this should probably not be allowed, here or in coclass, */ + /* but for now there's too many places in Wine IDL where it is to */ + /* even print a warning. */ + if (!(ifref->iface->defined)) continue; + if (!(requires = type_iface_get_requires(ifref->iface))) continue; + LIST_FOR_EACH_ENTRY(required, requires, ifref_t, entry) + { + int found = 0; + + LIST_FOR_EACH_ENTRY(tmp, ifaces, ifref_t, entry) + if ((found = type_is_equal(tmp->iface, required->iface))) break; + + if (!found) + error_loc("interface '%s' also requires interface '%s', " + "but runtimeclass '%s' does not implement it.\n", + ifref->iface->name, required->iface->name, runtimeclass->name); + } + } + return runtimeclass; }
@@ -593,8 +621,12 @@ type_t *type_apicontract_define(type_t *apicontract, attr_list_t *attrs)
int type_is_equal(const type_t *type1, const type_t *type2) { + if (type1 == type2) + return TRUE; if (type_get_type_detect_alias(type1) != type_get_type_detect_alias(type2)) return FALSE; + if (type1->namespace != type2->namespace) + return FALSE;
if (type1->name && type2->name) return !strcmp(type1->name, type2->name); diff --git a/tools/widl/typetree.h b/tools/widl/typetree.h index 8e04537ab4d..9866d2a1e98 100644 --- a/tools/widl/typetree.h +++ b/tools/widl/typetree.h @@ -53,7 +53,7 @@ type_t *type_new_encapsulated_union(char *name, var_t *switch_field, var_t *unio type_t *type_new_bitfield(type_t *field_type, const expr_t *bits); type_t *type_runtimeclass_declare(char *name, struct namespace *namespace); type_t *type_interface_declare(char *name, struct namespace *namespace); -type_t *type_interface_define(type_t *iface, attr_list_t *attrs, type_t *inherit, statement_list_t *stmts); +type_t *type_interface_define(type_t *iface, attr_list_t *attrs, type_t *inherit, statement_list_t *stmts, ifref_list_t *requires); type_t *type_dispinterface_declare(char *name); type_t *type_dispinterface_define(type_t *iface, attr_list_t *attrs, var_list_t *props, var_list_t *methods); type_t *type_dispinterface_define_from_iface(type_t *dispiface, attr_list_t *attrs, type_t *iface); @@ -181,6 +181,13 @@ static inline type_t *type_iface_get_inherit(const type_t *type) return type->details.iface->inherit; }
+static inline ifref_list_t *type_iface_get_requires(const type_t *type) +{ + type = type_get_real_type(type); + assert(type_get_type(type) == TYPE_INTERFACE); + return type->details.iface->requires; +} + static inline type_t *type_iface_get_async_iface(const type_t *type) { type = type_get_real_type(type); diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h index facfff21453..e22d425e85b 100644 --- a/tools/widl/widltypes.h +++ b/tools/widl/widltypes.h @@ -386,6 +386,7 @@ struct iface_details struct _type_t *inherit; struct _type_t *disp_inherit; struct _type_t *async_iface; + ifref_list_t *requires; };
struct module_details