From 1700f762985c9e7b128d7e0af9bd91dd8748b64c Mon Sep 17 00:00:00 2001
From: Not Zed <notzed@gmail.com>
Date: Tue, 1 Feb 2022 06:16:08 +1030
Subject: [PATCH] Some fixes for function argument names. Hack in a fix for
 typedef function pointers.

---
 src/export.cc | 174 ++++++++++++++++++++++++++++++++++++++++++++------
 src/list.h    |   7 ++
 2 files changed, 163 insertions(+), 18 deletions(-)

diff --git a/src/export.cc b/src/export.cc
index a37f0bd..611ab3f 100644
--- a/src/export.cc
+++ b/src/export.cc
@@ -420,11 +420,22 @@ static void export_cdesc(tree field, tree field_type, struct buffer *b) {
   Print a single parameter or field.
 */
 static void export_param(tree field, tree field_type, size_t field_size) {
+	static tree enclosing_type = NULL;
+
+	if (debug_level > 1) {
+		fprintf(stderr, "export_param (%s, %s)\n", ZTREE_CODE(field), ZTREE_CODE(field_type));
+		//fprintf(stderr, " field name '%s'\n", TYPE_IDENTIFIER(field) ? IDENTIFIER_POINTER(TYPE_IDENTIFIER(field)) : "<unknown>");
+		fprintf(stderr, " field_type name '%s'\n", TYPE_IDENTIFIER(field_type) ? IDENTIFIER_POINTER(TYPE_IDENTIFIER(field_type)) : "<unknown>");
+		debug_tree(field_type);
+	}
+
 	switch (TREE_CODE(field_type)) {
 	case VECTOR_TYPE:
 	case ARRAY_TYPE:
 	case POINTER_TYPE:
 	case REFERENCE_TYPE: {
+		tree base_type;
+		size_t base_size;
 		struct buffer b;
 
 		buffer_init(&b, 256);
@@ -432,10 +443,15 @@ static void export_param(tree field, tree field_type, size_t field_size) {
 		generate(" deref => '%s',", b.data);
 		free(b.data);
 
-		field_type = simple_type(field_type);
-		field_size = value_size(TYPE_SIZE(field_type));
+		base_type = simple_type(field_type);
+		base_size = value_size(TYPE_SIZE(base_type));
+
+		if (debug_level > 1)
+			fprintf(stderr, "recurse %s %s\n", ZTREE_CODE(field_type), ZTREE_CODE(base_type));
 
-		export_param(field, field_type, field_size);
+		enclosing_type = field_type;
+		export_param(field, base_type, base_size);
+		enclosing_type = NULL;
 		break;
 	}
 	case VOID_TYPE:
@@ -456,16 +472,27 @@ static void export_param(tree field, tree field_type, size_t field_size) {
 		struct buffer b;
 		tree root_type = TREE_TYPE(field);
 
+		if (root_type == NULL || !TYPE_IDENTIFIER(root_type))
+			root_type = enclosing_type;
+
 		// If this is a typedef we might have a name for the type, otherwise it's a signature based name
 		if (root_type && TYPE_IDENTIFIER(root_type)) {
 			generate(" type => 'call:%s', ", value_name(root_type));
 		} else {
-			if (debug_level > 0)
-				fprintf(stderr, "save for later param type %p\n", field_type);
+			// note it is added to todump in reverse
 			buffer_init(&b, 256);
 			export_desc(field, field_type, &b);
-			list_add(&todump, node_alloc(field_type, b.data));
+			list_addhead(&todump, node_alloc(field_type, b.data));
 			generate(" type => 'call:%s', ", b.data);
+			if (debug_level > 0) {
+				fprintf(stderr, "save for later param type %p root type %p '%s'\n", field_type, root_type, b.data);
+
+				if (root_type) {
+					fprintf(stderr, "type is '%s\n", ZTREE_CODE(root_type));
+					fprintf(stderr, "type name is '%s'\n", TYPE_IDENTIFIER(root_type) ? IDENTIFIER_POINTER(TYPE_IDENTIFIER(root_type)) : "<anon>");
+					fprintf(stderr, "target is '%s'\n", ZTREE_CODE(target_type(root_type)));
+				}
+			}
 		}
 
 		buffer_init(&b, 256);
@@ -530,13 +557,19 @@ static void export_params(tree func) {
 		for (tree param = TYPE_ARG_TYPES(func); param; param = TREE_CHAIN(param)) {
 			tree param_type = TREE_VALUE(param);
 
-			if (!TREE_CHAIN(param) && TREE_CODE(param_type) == VOID_TYPE)
+			if (!TREE_CHAIN(param) && TREE_CODE(param_type) == VOID_TYPE) {
+				if (id == 0) {
+					struct node *decl = stack_pull(&parameters);
+					if (debug_level > 0)
+						fprintf(stderr, "(pull parameter dummy '%s')\n", decl->name);
+				}
 				break;
+			}
 
 			struct node *decl = stack_pull(&parameters);
 			if (decl) {
 				if (debug_level > 0)
-					fprintf(stderr, "(pull parameter '%s')\n", decl->name);
+					fprintf(stderr, "(pull parameter args '%s')\n", decl->name);
 				stack_push(&args, decl);
 			} else
 				fprintf(stderr, "ERROR: parameter %d missing parameter declaration\n", id);
@@ -758,6 +791,8 @@ static void export_type(tree type, const char *names) {
 		break;
 	}
 	case FUNCTION_TYPE: {
+		int output_save = output_enabled;
+
 		// This is called for un-typedef'd function pointers.
 		// WHY IS THIS DIFFERENT TO ABOVE?
 		if (!names) {
@@ -766,8 +801,11 @@ static void export_type(tree type, const char *names) {
 				return;
 			names = IDENTIFIER_POINTER(name);
 		}
-		if (hash_lookup(&dumped, names))
-			return;
+		if (hash_lookup(&dumped, names)) {
+			if (debug_level > 0)
+				fprintf(stderr, " - type already output, supressing generation\n");
+			output_enabled = 0;
+		}
 		hash_put(&dumped, node_alloc(type, names));
 
 		if (debug_level > 1)
@@ -798,6 +836,8 @@ static void export_type(tree type, const char *names) {
 		export_params(type);
 		free(stack_pull(&context_stack));
 		generate("]},\n");
+
+		output_enabled = output_save;
 		break;
 	}
 	case RECORD_TYPE: // struct
@@ -880,8 +920,77 @@ static void export_type(tree type, const char *names) {
 		generate("]},\n");
 		break;
 	}
-	case FIELD_DECL:
+	case FIELD_DECL: {
+		if (!names) {
+			name = DECL_NAME(type);
+			if (name)
+				names = IDENTIFIER_POINTER(name);
+		}
+
+		deftype = TREE_TYPE(type);
+		target = target_type(deftype);
+
+		if (debug_level > 1) {
+			fprintf(stderr, "field_decl type is '%s\n", ZTREE_CODE(deftype));
+			fprintf(stderr, "type name is '%s'\n", TYPE_IDENTIFIER(deftype) ? IDENTIFIER_POINTER(TYPE_IDENTIFIER(deftype)) : "<anon>");
+			fprintf(stderr, "target is '%s'\n", ZTREE_CODE(target));
+		}
+
+		// nb almost same as next case below, but we don't save the param info here
+		if (TREE_CODE(target) == FUNCTION_TYPE && !TYPE_IDENTIFIER(deftype)) {
+			// We need to save the list of parameters for later,
+			// it's keyed on target
+			struct node *fwd = node_alloc(target, NULL);
+
+			if (debug_level > 0) {
+				struct buffer b;
+
+				buffer_init(&b, 256);
+				export_desc(deftype, target, &b);
+
+				fprintf(stderr, "save forward reference field function type %p '%s' '%s'\n", target, names, b.data);
+				// or should be todump?
+				free(b.data);
+			}
+
+			for (tree param = TYPE_ARG_TYPES(target); param != NULL; param = TREE_CHAIN(param)) {
+				tree param_type = TREE_VALUE(param);
+
+				if (TREE_CODE(param_type) == VOID_TYPE)
+					break;
+
+				struct node *decl = stack_pull(&parameters);
+				if (decl) {
+					if (debug_level > 0)
+						fprintf(stderr, "(pull parameter '%s')\n", decl->name);
+					stack_push(&fwd->list, decl);
+				} else
+					fprintf(stderr, "WARNING: stack is missing parameter name function %s\n", names);
+			}
+
+			hash_put_bytype(&forward_types, fwd);
+
+			// make sure it's dumped somewhere
+			// what if it's a typedef?
+
+			// ... we don't know if'ts a typedef though right?
+			// note it is added to todump in reverse
+			if (0) {
+				struct buffer b;
+
+				buffer_init(&b, 256);
+				export_desc(deftype, target, &b);
+				list_addhead(&todump, node_alloc(target, b.data));
+
+				if (debug_level > 0)
+					fprintf(stderr, "save for later param type %p '%s'\n", target, b.data);
+
+				free(b.data);
+			}
+		}
+
 		break;
+	}
 	case PARM_DECL: {
 		// capture PARM_DECLs so they can be used at next function declaration
 		if (!names) {
@@ -891,19 +1000,28 @@ static void export_type(tree type, const char *names) {
 		}
 		// if this is a function pointer typedef, need to suck out the arguments at this point
 		deftype = TREE_TYPE(type);
-
 		target = target_type(deftype);
 
-		//fprintf(stderr, "type is '%s\n", ZTREE_CODE(deftype));
-		//fprintf(stderr, "target is '%s\n", ZTREE_CODE(target));
+		if (debug_level > 1) {
+			fprintf(stderr, "type is '%s\n", ZTREE_CODE(deftype));
+			fprintf(stderr, "type name is '%s'\n", TYPE_IDENTIFIER(deftype) ? IDENTIFIER_POINTER(TYPE_IDENTIFIER(deftype)) : "<anon>");
+			fprintf(stderr, "target is '%s'\n", ZTREE_CODE(target));
+		}
 
-		if (TREE_CODE(target) == FUNCTION_TYPE) {
+		if (TREE_CODE(target) == FUNCTION_TYPE && !TYPE_IDENTIFIER(deftype)) {
 			// We need to save the list of parameters for later,
 			// it's keyed on target
 			struct node *fwd = node_alloc(target, NULL);
 
-			if (debug_level > 0)
-				fprintf(stderr, "save forward reference function type %p\n", target);
+			if (debug_level > 0) {
+				struct buffer b;
+
+				buffer_init(&b, 256);
+				export_desc(deftype, target, &b);
+
+				fprintf(stderr, "save forward reference function type %p '%s' '%s'\n", target, names, b.data);
+				free(b.data);
+			}
 
 			for (tree param = TYPE_ARG_TYPES(target); param != NULL; param = TREE_CHAIN(param)) {
 				tree param_type = TREE_VALUE(param);
@@ -921,6 +1039,25 @@ static void export_type(tree type, const char *names) {
 			}
 
 			hash_put_bytype(&forward_types, fwd);
+
+			// make sure it's dumped somewhere
+			// what if it's a typedef?
+
+			// ... we don't know if'ts a typedef though right?
+			// note it is added to todump in reverse
+			if (1) {
+				struct buffer b;
+
+				buffer_init(&b, 256);
+				export_desc(deftype, target, &b);
+				list_addhead(&todump, node_alloc(target, b.data));
+
+				if (debug_level > 0)
+					fprintf(stderr, "save for later param type %p '%s'\n", target, b.data);
+
+				free(b.data);
+			}
+
 		}
 
 		if (debug_level > 0)
@@ -962,7 +1099,8 @@ static void plugin_finish_decl(void *event_data, void *user_data) {
 
 static void plugin_finish(void *event_data, void *user_data) {
 	if (debug_level > 0)
-		fprintf(stderr, "plugin finish\n");
+		fprintf(stderr, "\n\n----------------------------------------\nplugin finish\n");
+	generate("# forward references:\n");
 	for (struct node *n = todump.head; n; n=n->next) {
 		if (COMPLETE_TYPE_P(n->type)) {
 			if (n->name[0]) {
diff --git a/src/list.h b/src/list.h
index 0ba636f..4a96688 100644
--- a/src/list.h
+++ b/src/list.h
@@ -112,6 +112,13 @@ static void list_add(struct list *list, struct node *node) {
 	}
 }
 
+static void list_addhead(struct list *list, struct node *node) {
+	node->next = list->head;
+	list->head = node;
+	if (!list->tail)
+		list->tail = node;
+}
+
 static struct node *list_remhead(struct list *list) {
 	struct node *node = list->head;
 
-- 
2.39.5