| 1097 | } |
| 1098 | |
| 1099 | static const CBMType *eval_method_invocation(JavaLSPContext *ctx, TSNode node) { |
| 1100 | TSNode obj = ts_node_child_by_field_name(node, "object", 6); |
| 1101 | TSNode name_node = ts_node_child_by_field_name(node, "name", 4); |
| 1102 | if (ts_node_is_null(name_node)) |
| 1103 | return cbm_type_unknown(); |
| 1104 | char *mname = java_node_text(ctx, name_node); |
| 1105 | if (!mname) |
| 1106 | return cbm_type_unknown(); |
| 1107 | int arity = count_call_args(node); |
| 1108 | |
| 1109 | /* No receiver: `foo()` — method is on enclosing class or static import. */ |
| 1110 | if (ts_node_is_null(obj)) { |
| 1111 | if (ctx->enclosing_class_qn) { |
| 1112 | const CBMRegisteredFunc *f = |
| 1113 | java_lookup_method(ctx, ctx->enclosing_class_qn, mname, arity); |
| 1114 | if (f) |
| 1115 | return java_return_type_of(f); |
| 1116 | } |
| 1117 | for (int i = 0; i < ctx->import_count; i++) { |
| 1118 | if (ctx->import_kinds[i] != CBM_JAVA_IMPORT_STATIC) |
| 1119 | continue; |
| 1120 | if (strcmp(ctx->import_local_names[i], mname) != 0) |
| 1121 | continue; |
| 1122 | const char *target = ctx->import_target_qns[i]; |
| 1123 | const char *last_dot = strrchr(target, '.'); |
| 1124 | if (!last_dot) |
| 1125 | continue; |
| 1126 | char *cls = cbm_arena_strndup(ctx->arena, target, (size_t)(last_dot - target)); |
| 1127 | const CBMRegisteredFunc *f = java_lookup_method(ctx, cls, mname, arity); |
| 1128 | if (f) |
| 1129 | return java_return_type_of(f); |
| 1130 | } |
| 1131 | return cbm_type_unknown(); |
| 1132 | } |
| 1133 | |
| 1134 | /* `super.method()` */ |
| 1135 | if (strcmp(ts_node_type(obj), "super") == 0) { |
| 1136 | const char *super_qn = |
| 1137 | ctx->enclosing_super_qn ? ctx->enclosing_super_qn : "java.lang.Object"; |
| 1138 | const CBMRegisteredFunc *f = java_lookup_method(ctx, super_qn, mname, arity); |
| 1139 | if (f) |
| 1140 | return java_return_type_of(f); |
| 1141 | return cbm_type_unknown(); |
| 1142 | } |
| 1143 | |
| 1144 | /* Static call: `ClassName.method()` where obj is an identifier matching a |
| 1145 | * known type. */ |
| 1146 | if (strcmp(ts_node_type(obj), "identifier") == 0) { |
| 1147 | char *oname = java_node_text(ctx, obj); |
| 1148 | if (oname) { |
| 1149 | const char *cls_qn = java_resolve_type_name(ctx, oname); |
| 1150 | if (cls_qn) { |
| 1151 | /* Only treat as static if there's no local var of that name. */ |
| 1152 | if (cbm_type_is_unknown(cbm_scope_lookup(ctx->current_scope, oname))) { |
| 1153 | const CBMRegisteredFunc *f = java_lookup_method(ctx, cls_qn, mname, arity); |
| 1154 | if (f) |
| 1155 | return java_return_type_of(f); |
| 1156 | } |
no test coverage detected