Parse a type-text into a CBMType, with full inner-class qualification. * `parent_class` is the QN of the enclosing class (NULL at file scope), used * to qualify unqualified inner-class references. `reg` is consulted to * confirm matches before committing to a candidate QN. * * Preserves generic template arguments: "Consumer " parses to a * TEMPLATE("java.util.function.Consumer", [Stri
| 3065 | * TEMPLATE("java.util.function.Consumer", [String]) so the SAM-binder |
| 3066 | * downstream can substitute the lambda's parameter type correctly. */ |
| 3067 | static const CBMType *parse_param_text_full(CBMArena *a, const char *text, const char *parent_class, |
| 3068 | const char *module_qn, const CBMTypeRegistry *reg) { |
| 3069 | if (!text) |
| 3070 | return cbm_type_unknown(); |
| 3071 | int dim = 0; |
| 3072 | const char *no_arr = unwrap_array_text(a, text, &dim); |
| 3073 | const char *no_gen = strip_generics(a, no_arr); |
| 3074 | |
| 3075 | /* Extract the inside-of-angles for generic-arg recursion. */ |
| 3076 | const char *gen_args_inner = NULL; |
| 3077 | if (no_arr) { |
| 3078 | const char *lt = strchr(no_arr, '<'); |
| 3079 | if (lt) { |
| 3080 | /* find matching '>' at depth 0 */ |
| 3081 | int depth = 0; |
| 3082 | const char *gt = NULL; |
| 3083 | for (const char *p = lt; *p; p++) { |
| 3084 | if (*p == '<') |
| 3085 | depth++; |
| 3086 | else if (*p == '>') { |
| 3087 | depth--; |
| 3088 | if (depth == 0) { |
| 3089 | gt = p; |
| 3090 | break; |
| 3091 | } |
| 3092 | } |
| 3093 | } |
| 3094 | if (gt && gt > lt + 1) { |
| 3095 | gen_args_inner = cbm_arena_strndup(a, lt + 1, (size_t)(gt - lt - 1)); |
| 3096 | } |
| 3097 | } |
| 3098 | } |
| 3099 | |
| 3100 | const CBMType *base = NULL; |
| 3101 | if (no_gen && is_java_primitive(no_gen)) { |
| 3102 | base = cbm_type_builtin(a, no_gen); |
| 3103 | } else if (no_gen) { |
| 3104 | if (strchr(no_gen, '.')) { |
| 3105 | base = cbm_type_named(a, no_gen); |
| 3106 | } else { |
| 3107 | /* Try java.lang well-knowns. */ |
| 3108 | for (int i = 0; JAVA_LANG_TYPES[i]; i++) { |
| 3109 | if (strcmp(JAVA_LANG_TYPES[i], no_gen) == 0) { |
| 3110 | base = cbm_type_named(a, cbm_arena_sprintf(a, "java.lang.%s", no_gen)); |
| 3111 | break; |
| 3112 | } |
| 3113 | } |
| 3114 | /* Walk parent_class chain trying parent.X, parent.parent.X, ... */ |
| 3115 | if (!base && parent_class && reg) { |
| 3116 | const char *cur = parent_class; |
| 3117 | while (cur) { |
| 3118 | const char *cand = cbm_arena_sprintf(a, "%s.%s", cur, no_gen); |
| 3119 | if (cbm_registry_lookup_type(reg, cand)) { |
| 3120 | base = cbm_type_named(a, cand); |
| 3121 | break; |
| 3122 | } |
| 3123 | const char *last_dot = strrchr(cur, '.'); |
| 3124 | if (!last_dot) |
no test coverage detected