MCPcopy Create free account
hub / github.com/DeusData/codebase-memory-mcp / parse_narrowing_one

Function parse_narrowing_one

internal/cbm/lsp/php_lsp.c:1735–1881  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

1733}
1734
1735static int parse_narrowing_one(PHPLSPContext *ctx, TSNode cond, php_narrowing_t *out) {
1736 if (ts_node_is_null(cond))
1737 return 0;
1738 const char *kind = ts_node_type(cond);
1739 if (strcmp(kind, "parenthesized_expression") == 0) {
1740 uint32_t nc = ts_node_child_count(cond);
1741 for (uint32_t i = 0; i < nc; i++) {
1742 TSNode c = ts_node_child(cond, i);
1743 if (!ts_node_is_null(c) && ts_node_is_named(c)) {
1744 return parse_narrowing_one(ctx, c, out);
1745 }
1746 }
1747 return 0;
1748 }
1749
1750 /* `$x instanceof Foo` — emitted as binary_expression with operator
1751 * "instanceof" in tree-sitter-php. */
1752 if (strcmp(kind, "binary_expression") == 0) {
1753 TSNode left = ts_node_child_by_field_name(cond, "left", 4);
1754 TSNode op = ts_node_child_by_field_name(cond, "operator", 8);
1755 TSNode right = ts_node_child_by_field_name(cond, "right", 5);
1756 if (ts_node_is_null(left) || ts_node_is_null(right))
1757 return false;
1758 char *opt = !ts_node_is_null(op) ? php_node_text(ctx, op) : NULL;
1759 if (opt && strcmp(opt, "instanceof") == 0) {
1760 if (!node_is(left, "variable_name"))
1761 return false;
1762 char *vt = php_node_text(ctx, left);
1763 if (!vt)
1764 return false;
1765 const char *vname = (vt[0] == '$') ? vt + 1 : vt;
1766 char *rt = php_node_text(ctx, right);
1767 if (!rt)
1768 return false;
1769 const char *resolved = php_resolve_class_name(ctx, rt);
1770 if (!resolved)
1771 return false;
1772 out->var_name = cbm_arena_strdup(ctx->arena, vname);
1773 out->type = cbm_type_named(ctx->arena, resolved);
1774 return true;
1775 }
1776 /* `$x !== null` / `$x != null` / `null !== $x` — narrow to "non-null":
1777 * we keep the existing scope type, so this is a no-op for type
1778 * purposes but suppresses null branches downstream. We don't
1779 * subtract nullable so just return false here. */
1780 }
1781
1782 /* `is_string($x)` / `is_int($x)` / `array_key_exists(...)` /
1783 * `method_exists($x, 'foo')` / `is_a($x, Foo::class)` / ... */
1784 if (strcmp(kind, "function_call_expression") == 0) {
1785 TSNode fn = ts_node_child_by_field_name(cond, "function", 8);
1786 TSNode args = ts_node_child_by_field_name(cond, "arguments", 9);
1787 if (ts_node_is_null(fn))
1788 return false;
1789 char *name = php_node_text(ctx, fn);
1790 if (!name)
1791 return false;
1792 /* `is_a($x, Foo::class)` and `is_a($x, 'Foo')` narrow $x to Foo. */

Callers 1

parse_narrowing_collectFunction · 0.85

Calls 7

php_node_textFunction · 0.85
node_isFunction · 0.85
php_resolve_class_nameFunction · 0.85
cbm_type_namedFunction · 0.85
is_func_to_builtinFunction · 0.85
cbm_type_builtinFunction · 0.85
cbm_arena_strdupFunction · 0.50

Tested by

no test coverage detected