[2/3] scanner: enforce correct argument type for enums

Submitted by Auke Booij on June 26, 2015, 2:02 p.m.

Details

Message ID 1435327367-6993-3-git-send-email-auke@tulcod.com
State Superseded
Delegated to: Bryce Harrington
Headers show

Not browsing as part of any series.

Commit Message

Auke Booij June 26, 2015, 2:02 p.m.
The scanner now checks whether arguments that have an associated
<enum> have the right type.
An argument with an enum attribute must be of type int or uint,
and if the <enum> with that name has the bitfield attribute
set to true, then the argument must be of type uint.
---
 src/scanner.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 67 insertions(+), 1 deletion(-)

--
2.4.4

Patch hide | download patch | download mbox

diff --git a/src/scanner.c b/src/scanner.c
index 7d8cfb9..75dda55 100644
--- a/src/scanner.c
+++ b/src/scanner.c
@@ -126,6 +126,7 @@  struct arg {
 	char *interface_name;
 	struct wl_list link;
 	char *summary;
+	char *enumeration_name;
 };

 struct enumeration {
@@ -134,6 +135,7 @@  struct enumeration {
 	struct wl_list entry_list;
 	struct wl_list link;
 	struct description *description;
+	int bitfield;
 };

 struct entry {
@@ -326,7 +328,7 @@  start_element(void *data, const char *element_name, const char **atts)
 	struct entry *entry;
 	struct description *description;
 	const char *name, *type, *interface_name, *value, *summary, *since;
-	const char *allow_null;
+	const char *allow_null, *enumeration_name, *bitfield;
 	char *end;
 	int i, version;

@@ -340,6 +342,8 @@  start_element(void *data, const char *element_name, const char **atts)
 	description = NULL;
 	since = NULL;
 	allow_null = NULL;
+	enumeration_name = NULL;
+	bitfield = NULL;
 	for (i = 0; atts[i]; i += 2) {
 		if (strcmp(atts[i], "name") == 0)
 			name = atts[i + 1];
@@ -357,6 +361,10 @@  start_element(void *data, const char *element_name, const char **atts)
 			since = atts[i + 1];
 		if (strcmp(atts[i], "allow-null") == 0)
 			allow_null = atts[i + 1];
+		if (strcmp(atts[i], "enum") == 0)
+			enumeration_name = atts[i + 1];
+		if (strcmp(atts[i], "bitfield") == 0)
+			bitfield = atts[i + 1];
 	}

 	ctx->character_data_length = 0;
@@ -488,6 +496,11 @@  start_element(void *data, const char *element_name, const char **atts)
 		else
 			fail(&ctx->loc, "invalid value for allow-null attribute (%s)", allow_null);

+		if (enumeration_name == NULL || strcmp(enumeration_name, "") == 0)
+			arg->enumeration_name = NULL;
+		else
+			arg->enumeration_name = xstrdup(enumeration_name);
+
 		if (allow_null != NULL && !is_nullable_type(arg))
 			fail(&ctx->loc, "allow-null is only valid for objects, strings, and arrays");

@@ -507,6 +520,13 @@  start_element(void *data, const char *element_name, const char **atts)
 		enumeration->description = NULL;
 		wl_list_init(&enumeration->entry_list);

+		if (bitfield == NULL || strcmp(bitfield, "false") == 0)
+			enumeration->bitfield = 0;
+		else if (strcmp(bitfield, "true") == 0)
+			enumeration->bitfield =1;
+		else
+			fail(&ctx->loc, "invalid value for bitfield attribute (%s)", bitfield);
+
 		wl_list_insert(ctx->interface->enumeration_list.prev,
 			       &enumeration->link);

@@ -545,6 +565,46 @@  start_element(void *data, const char *element_name, const char **atts)
 }

 static void
+verify_arguments(struct parse_context *ctx, struct wl_list *messages, struct wl_list *enumerations)
+{
+	struct message *m;
+	wl_list_for_each(m, messages, link) {
+		struct arg *a;
+		wl_list_for_each(a, &m->arg_list, link) {
+			struct enumeration *e, *f;
+
+			if (!a->enumeration_name)
+				continue;
+
+			f = NULL;
+			wl_list_for_each(e, enumerations, link) {
+				if(strcmp(e->name, a->enumeration_name) == 0)
+					f = e;
+			}
+
+			if (f == NULL)
+				fail(&ctx->loc,
+				     "could not find enumeration %s",
+				     a->enumeration_name);
+
+			switch (a->type) {
+			case INT:
+				if (f->bitfield)
+					fail(&ctx->loc,
+					     "bitfield-style enum must be referenced by uint");
+				break;
+			case UNSIGNED:
+				break;
+			default:
+				fail(&ctx->loc,
+				     "enumeration-style argument has wrong type");
+			}
+		}
+	}
+
+}
+
+static void
 end_element(void *data, const XML_Char *name)
 {
 	struct parse_context *ctx = data;
@@ -567,6 +627,12 @@  end_element(void *data, const XML_Char *name)
 			     ctx->enumeration->name);
 		}
 		ctx->enumeration = NULL;
+	} else if (strcmp(name, "interface") == 0) {
+		struct interface *i = ctx->interface;
+
+		verify_arguments(ctx, &i->request_list, &i->enumeration_list);
+		verify_arguments(ctx, &i->event_list, &i->enumeration_list);
+
 	}
 }