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
| 2982 | * TEMPLATE("java.util.function.Consumer", [String]) so the SAM-binder |
| 2983 | * downstream can substitute the lambda's parameter type correctly. */ |
| 2984 | static const CBMType *parse_param_text_full(CBMArena *a, const char *text, const char *parent_class, |
| 2985 | const char *module_qn, const CBMTypeRegistry *reg) { |
| 2986 | if (!text) |
| 2987 | return cbm_type_unknown(); |
| 2988 | int dim = 0; |
| 2989 | const char *no_arr = unwrap_array_text(a, text, &dim); |
| 2990 | const char *no_gen = strip_generics(a, no_arr); |
| 2991 | |
| 2992 | /* Extract the inside-of-angles for generic-arg recursion. */ |
| 2993 | const char *gen_args_inner = NULL; |
| 2994 | if (no_arr) { |
| 2995 | const char *lt = strchr(no_arr, '<'); |
| 2996 | if (lt) { |
| 2997 | /* find matching '>' at depth 0 */ |
| 2998 | int depth = 0; |
| 2999 | const char *gt = NULL; |
| 3000 | for (const char *p = lt; *p; p++) { |
| 3001 | if (*p == '<') |
| 3002 | depth++; |
| 3003 | else if (*p == '>') { |
| 3004 | depth--; |
| 3005 | if (depth == 0) { |
| 3006 | gt = p; |
| 3007 | break; |
| 3008 | } |
| 3009 | } |
| 3010 | } |
| 3011 | if (gt && gt > lt + 1) { |
| 3012 | gen_args_inner = cbm_arena_strndup(a, lt + 1, (size_t)(gt - lt - 1)); |
| 3013 | } |
| 3014 | } |
| 3015 | } |
| 3016 | |
| 3017 | const CBMType *base = NULL; |
| 3018 | if (no_gen && is_java_primitive(no_gen)) { |
| 3019 | base = cbm_type_builtin(a, no_gen); |
| 3020 | } else if (no_gen) { |
| 3021 | if (strchr(no_gen, '.')) { |
| 3022 | base = cbm_type_named(a, no_gen); |
| 3023 | } else { |
| 3024 | /* Try java.lang well-knowns. */ |
| 3025 | for (int i = 0; JAVA_LANG_TYPES[i]; i++) { |
| 3026 | if (strcmp(JAVA_LANG_TYPES[i], no_gen) == 0) { |
| 3027 | base = cbm_type_named(a, cbm_arena_sprintf(a, "java.lang.%s", no_gen)); |
| 3028 | break; |
| 3029 | } |
| 3030 | } |
| 3031 | /* Walk parent_class chain trying parent.X, parent.parent.X, ... */ |
| 3032 | if (!base && parent_class && reg) { |
| 3033 | const char *cur = parent_class; |
| 3034 | while (cur) { |
| 3035 | const char *cand = cbm_arena_sprintf(a, "%s.%s", cur, no_gen); |
| 3036 | if (cbm_registry_lookup_type(reg, cand)) { |
| 3037 | base = cbm_type_named(a, cand); |
| 3038 | break; |
| 3039 | } |
| 3040 | const char *last_dot = strrchr(cur, '.'); |
| 3041 | if (!last_dot) |
no test coverage detected