[PATCH 4/4] widl: Support WinRT contract attribute.

Rémi Bernon rbernon at codeweavers.com
Mon Nov 23 05:24:57 CST 2020


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 include/windows.foundation.idl | 14 +++----
 tools/widl/header.c            | 72 ++++++++++++++++++++++++++++++++--
 tools/widl/parser.l            |  1 +
 tools/widl/parser.y            | 10 +++++
 tools/widl/widltypes.h         |  1 +
 5 files changed, 88 insertions(+), 10 deletions(-)

diff --git a/include/windows.foundation.idl b/include/windows.foundation.idl
index 2a38e9f671b..5e17062f399 100644
--- a/include/windows.foundation.idl
+++ b/include/windows.foundation.idl
@@ -28,7 +28,7 @@ import "windowscontracts.idl";
 
 namespace Windows {
     namespace Foundation {
-        [version(0x06020000)]
+        [contract(Windows.Foundation.FoundationContract, 1.0)]
         enum PropertyType {
             Empty       = 0,
             UInt8       = 1,
@@ -73,19 +73,19 @@ namespace Windows {
             OtherTypeArray   = 1044
         };
 
-        [version(0x06020000)]
+        [contract(Windows.Foundation.FoundationContract, 1.0)]
         struct Point {
             FLOAT X;
             FLOAT Y;
         };
 
-        [version(0x06020000)]
+        [contract(Windows.Foundation.FoundationContract, 1.0)]
         struct Size {
             FLOAT Width;
             FLOAT Height;
         };
 
-        [version(0x06020000)]
+        [contract(Windows.Foundation.FoundationContract, 1.0)]
         struct Rect {
             FLOAT X;
             FLOAT Y;
@@ -93,18 +93,18 @@ namespace Windows {
             FLOAT Height;
         };
 
-        [version(0x06020000)]
+        [contract(Windows.Foundation.FoundationContract, 1.0)]
         struct DateTime {
             INT64 UniversalTime;
         };
 
-        [version(0x06020000)]
+        [contract(Windows.Foundation.FoundationContract, 1.0)]
         struct TimeSpan {
             INT64 Duration;
         };
 
         [
-            version(0x06030000),
+            contract(Windows.Foundation.FoundationContract, 1.0),
             uuid(96369f54-8eb6-48f0-abce-c1b211e627c3)
         ]
         interface IStringable : IInspectable
diff --git a/tools/widl/header.c b/tools/widl/header.c
index 657ce50c679..223ab5c5ca9 100644
--- a/tools/widl/header.c
+++ b/tools/widl/header.c
@@ -45,6 +45,11 @@ generic_handle_list_t generic_handle_list = LIST_INIT(generic_handle_list);
 
 static void write_type_v(FILE *f, const decl_spec_t *t, int is_field, int declonly, const char *name, enum name_type name_type);
 
+static void write_winrt_type_comments(FILE *header, const type_t *type);
+
+static void write_apicontract_guard_start(FILE *header, const expr_t *expr);
+static void write_apicontract_guard_end(FILE *header, const expr_t *expr);
+
 static void indent(FILE *h, int delta)
 {
   int c;
@@ -218,7 +223,9 @@ static void write_fields(FILE *h, var_list_t *fields, enum name_type name_type)
     }
 
     LIST_FOR_EACH_ENTRY( v, fields, var_t, entry ) {
+        expr_t *contract = get_attrp(v->attrs, ATTR_CONTRACT);
         if (!v || !v->declspec.type) continue;
+        if (contract) write_apicontract_guard_start(h, contract);
 
         indent(h, 0);
         name = v->name;
@@ -252,6 +259,7 @@ static void write_fields(FILE *h, var_list_t *fields, enum name_type name_type)
         }
         write_type_v(h, &v->declspec, TRUE, v->declonly, name, name_type);
         fprintf(h, ";\n");
+        if (contract) write_apicontract_guard_end(h, contract);
     }
 }
 
@@ -261,6 +269,8 @@ static void write_enums(FILE *h, var_list_t *enums, const char *enum_name)
   if (!enums) return;
   LIST_FOR_EACH_ENTRY( v, enums, var_t, entry )
   {
+    expr_t *contract = get_attrp(v->attrs, ATTR_CONTRACT);
+    if (contract) write_apicontract_guard_start(h, contract);
     if (v->name) {
       indent(h, 0);
       if(!enum_name)
@@ -273,8 +283,9 @@ static void write_enums(FILE *h, var_list_t *enums, const char *enum_name)
       }
     }
     if (list_next( enums, &v->entry )) fprintf(h, ",\n");
+    else fprintf(h, "\n");
+    if (contract) write_apicontract_guard_end(h, contract);
   }
-  fprintf(h, "\n");
 }
 
 int needs_space_after(type_t *t)
@@ -563,7 +574,9 @@ static void write_type_definition(FILE *f, type_t *t, int declonly)
     int in_namespace = t->namespace && !is_global_namespace(t->namespace);
     int save_written = t->written;
     decl_spec_t ds = {.type = t};
+    expr_t *contract = get_attrp(t->attrs, ATTR_CONTRACT);
 
+    if (contract) write_apicontract_guard_start(f, contract);
     if(in_namespace) {
         fprintf(f, "#ifdef __cplusplus\n");
         fprintf(f, "} /* extern \"C\" */\n");
@@ -581,6 +594,7 @@ static void write_type_definition(FILE *f, type_t *t, int declonly)
         fprintf(f, ";\n");
         fprintf(f, "#endif\n\n");
     }
+    if (contract) write_apicontract_guard_end(f, contract);
 }
 
 void write_type_decl(FILE *f, const decl_spec_t *t, const char *name)
@@ -1468,12 +1482,55 @@ static char *format_apicontract_macro(const type_t *type)
     return name;
 }
 
+static void write_winrt_type_comments(FILE *header, const type_t *type)
+{
+    expr_t *contract = get_attrp(type->attrs, ATTR_CONTRACT);
+    fprintf(header, " *\n");
+    if (contract)
+    {
+        const type_t *type = contract->u.tref.type;
+        char *name = format_namespace(type->namespace, "", ".", type->name, NULL);
+        int ver = contract->ref->u.lval;
+        fprintf(header, " * Introduced to %s in version %d.%d\n *\n", name, (ver >> 16) & 0xffff, ver & 0xffff);
+        free(name);
+    }
+}
+
+static void write_apicontract_guard_start(FILE *header, const expr_t *expr)
+{
+    const type_t *type;
+    char *name;
+    int ver;
+    if (!winrt_mode) return;
+    type = expr->u.tref.type;
+    ver = expr->ref->u.lval;
+    name = format_apicontract_macro(type);
+    fprintf(header, "#if %s_VERSION >= %#x\n", name, ver);
+    free(name);
+}
+
+static void write_apicontract_guard_end(FILE *header, const expr_t *expr)
+{
+    const type_t *type;
+    char *name;
+    int ver;
+    if (!winrt_mode) return;
+    type = expr->u.tref.type;
+    ver = expr->ref->u.lval;
+    name = format_apicontract_macro(type);
+    fprintf(header, "#endif /* %s_VERSION >= %#x */\n", name, ver);
+    free(name);
+}
+
 static void write_com_interface_start(FILE *header, const type_t *iface)
 {
   int dispinterface = is_attr(iface->attrs, ATTR_DISPINTERFACE);
+  expr_t *contract = get_attrp(iface->attrs, ATTR_CONTRACT);
   fprintf(header, "/*****************************************************************************\n");
   fprintf(header, " * %s %sinterface\n", iface->name, dispinterface ? "disp" : "");
+  if (winrt_mode) write_winrt_type_comments(header, iface);
   fprintf(header, " */\n");
+  if (contract) write_apicontract_guard_start(header, contract);
   fprintf(header,"#ifndef __%s_%sINTERFACE_DEFINED__\n", iface->c_name, dispinterface ? "DISP" : "");
   fprintf(header,"#define __%s_%sINTERFACE_DEFINED__\n\n", iface->c_name, dispinterface ? "DISP" : "");
 }
@@ -1482,6 +1539,7 @@ static void write_com_interface_end(FILE *header, type_t *iface)
 {
   int dispinterface = is_attr(iface->attrs, ATTR_DISPINTERFACE);
   const UUID *uuid = get_attrp(iface->attrs, ATTR_UUID);
+  expr_t *contract = get_attrp(iface->attrs, ATTR_CONTRACT);
   type_t *type;
 
   if (uuid)
@@ -1559,17 +1617,22 @@ static void write_com_interface_end(FILE *header, type_t *iface)
     write_locals(header, iface, FALSE);
     fprintf(header, "\n");
   }
-  fprintf(header,"#endif  /* __%s_%sINTERFACE_DEFINED__ */\n\n", iface->c_name, dispinterface ? "DISP" : "");
+  fprintf(header, "#endif  /* __%s_%sINTERFACE_DEFINED__ */\n", iface->c_name, dispinterface ? "DISP" : "");
+  if (contract) write_apicontract_guard_end(header, contract);
+  fprintf(header, "\n");
 }
 
 static void write_rpc_interface_start(FILE *header, const type_t *iface)
 {
   unsigned int ver = get_attrv(iface->attrs, ATTR_VERSION);
   const var_t *var = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE);
+  expr_t *contract = get_attrp(iface->attrs, ATTR_CONTRACT);
 
   fprintf(header, "/*****************************************************************************\n");
   fprintf(header, " * %s interface (v%d.%d)\n", iface->name, MAJORVERSION(ver), MINORVERSION(ver));
+  if (winrt_mode) write_winrt_type_comments(header, iface);
   fprintf(header, " */\n");
+  if (contract) write_apicontract_guard_start(header, contract);
   fprintf(header,"#ifndef __%s_INTERFACE_DEFINED__\n", iface->name);
   fprintf(header,"#define __%s_INTERFACE_DEFINED__\n\n", iface->name);
   if (var)
@@ -1594,7 +1657,10 @@ static void write_rpc_interface_start(FILE *header, const type_t *iface)
 
 static void write_rpc_interface_end(FILE *header, const type_t *iface)
 {
-  fprintf(header,"\n#endif  /* __%s_INTERFACE_DEFINED__ */\n\n", iface->name);
+  expr_t *contract = get_attrp(iface->attrs, ATTR_CONTRACT);
+  fprintf(header, "\n#endif  /* __%s_INTERFACE_DEFINED__ */\n", iface->name);
+  if (contract) write_apicontract_guard_end(header, contract);
+  fprintf(header, "\n");
 }
 
 static void write_coclass(FILE *header, type_t *cocl)
diff --git a/tools/widl/parser.l b/tools/widl/parser.l
index 6a9bb65a483..9dce03577c6 100644
--- a/tools/widl/parser.l
+++ b/tools/widl/parser.l
@@ -339,6 +339,7 @@ static const struct keyword attr_keywords[] =
 	{"context_handle",              tCONTEXTHANDLE,             0},
 	{"context_handle_noserialize",  tCONTEXTHANDLENOSERIALIZE,  0},
 	{"context_handle_serialize",    tCONTEXTHANDLENOSERIALIZE,  0},
+	{"contract",                    tCONTRACT,                  1},
 	{"contractversion",             tCONTRACTVERSION,           1},
 	{"control",                     tCONTROL,                   0},
 	{"custom",                      tCUSTOM,                    0},
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index 5b4bd518a0b..1d413ca74f4 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -181,6 +181,7 @@ static typelib_t *current_typelib;
 %token tCALLAS tCALLBACK tCASE tCDECL tCHAR tCOCLASS tCODE tCOMMSTATUS
 %token tCONST tCONTEXTHANDLE tCONTEXTHANDLENOSERIALIZE
 %token tCONTEXTHANDLESERIALIZE
+%token tCONTRACT
 %token tCONTRACTVERSION
 %token tCONTROL tCPPQUOTE
 %token tCUSTOM
@@ -271,6 +272,7 @@ static typelib_t *current_typelib;
 %type <str_list> str_list
 %type <expr> m_expr expr expr_const expr_int_const array m_bitfield
 %type <expr_list> m_exprs /* exprs expr_list */ expr_list_int_const
+%type <expr> contract_req
 %type <type> interfacehdr
 %type <stgclass> storage_cls_spec
 %type <type_qualifier> type_qualifier m_type_qual_list
@@ -508,6 +510,12 @@ contract_ver:
 	| aNUM '.' aNUM				{ $$ = MAKEVERSION($3, $1); }
 	;
 
+contract_req: decl_spec ',' contract_ver	{ if ($1->type->type_type != TYPE_APICONTRACT)
+						      error_loc("type %s is not an apicontract\n", $1->type->name);
+						  $$ = make_exprl(EXPR_NUM, $3);
+						  $$ = make_exprt(EXPR_GTREQL, declare_var(NULL, $1, make_declarator(NULL), 0), $$);
+						}
+
 attribute:					{ $$ = NULL; }
 	| tAGGREGATABLE				{ $$ = make_attr(ATTR_AGGREGATABLE); }
 	| tANNOTATION '(' aSTRING ')'		{ $$ = make_attrp(ATTR_ANNOTATION, $3); }
@@ -523,6 +531,7 @@ attribute:					{ $$ = NULL; }
 	| tCONTEXTHANDLE			{ $$ = make_attrv(ATTR_CONTEXTHANDLE, 0); }
 	| tCONTEXTHANDLENOSERIALIZE		{ $$ = make_attrv(ATTR_CONTEXTHANDLE, 0); /* RPC_CONTEXT_HANDLE_DONT_SERIALIZE */ }
 	| tCONTEXTHANDLESERIALIZE		{ $$ = make_attrv(ATTR_CONTEXTHANDLE, 0); /* RPC_CONTEXT_HANDLE_SERIALIZE */ }
+	| tCONTRACT '(' contract_req ')'	{ $$ = make_attrp(ATTR_CONTRACT, $3); }
 	| tCONTRACTVERSION '(' contract_ver ')'	{ $$ = make_attrv(ATTR_CONTRACTVERSION, $3); }
 	| tCONTROL				{ $$ = make_attr(ATTR_CONTROL); }
 	| tCUSTOM '(' uuid_string ',' expr_const ')' { $$ = make_custom_attr($3, $5); }
@@ -2180,6 +2189,7 @@ struct allowed_attr allowed_attr[] =
     /* ATTR_CODE */                { 0, 1, 0,  1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "code" },
     /* ATTR_COMMSTATUS */          { 0, 0, 0,  0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "comm_status" },
     /* ATTR_CONTEXTHANDLE */       { 1, 0, 0,  0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "context_handle" },
+    /* ATTR_CONTRACT */            { 0, 0, 0,  1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, "contract" },
     /* ATTR_CONTRACTVERSION */     { 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, "contractversion" },
     /* ATTR_CONTROL */             { 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, "control" },
     /* ATTR_CUSTOM */              { 0, 0, 1,  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, "custom" },
diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h
index 878650d9c27..d5862426ad4 100644
--- a/tools/widl/widltypes.h
+++ b/tools/widl/widltypes.h
@@ -84,6 +84,7 @@ enum attr_type
     ATTR_CODE,
     ATTR_COMMSTATUS,
     ATTR_CONTEXTHANDLE,
+    ATTR_CONTRACT,
     ATTR_CONTRACTVERSION,
     ATTR_CONTROL,
     ATTR_CUSTOM,
-- 
2.29.2




More information about the wine-devel mailing list