| 1095 | } |
| 1096 | |
| 1097 | static bool is_binding_occurrence(CBMExtractCtx *ctx, TSNode node, const CBMLangSpec *spec, |
| 1098 | WalkState *state) { |
| 1099 | const CBMOccurrenceSpec *occurrence = &occurrence_specs[ctx->language]; |
| 1100 | if (is_exact_language_binding(ctx, node, state)) { |
| 1101 | return true; |
| 1102 | } |
| 1103 | if (is_policy_binding(ctx, node, occurrence)) { |
| 1104 | return true; |
| 1105 | } |
| 1106 | |
| 1107 | TSNode current = node; |
| 1108 | TSTreeCursor *cursor = reset_occurrence_cursor(state, node); |
| 1109 | while (!ts_node_is_null(current)) { |
| 1110 | TSNode parent; |
| 1111 | const char *field; |
| 1112 | if (!occurrence_parent(cursor, current, &parent, &field)) { |
| 1113 | break; |
| 1114 | } |
| 1115 | if (is_value_field(field)) { |
| 1116 | return false; |
| 1117 | } |
| 1118 | /* A declaration container binds its name/pattern, not the symbols used |
| 1119 | * by its type annotation. Both TypeScript (`cfg: Config`) and Go |
| 1120 | * (`cfg Config`) expose that annotation through the exact `type` field; |
| 1121 | * stop before the whole-parameter binding rule can swallow `Config`. |
| 1122 | * The emitted occurrence remains an ordinary USAGE, never a callable |
| 1123 | * reference merely because the target happens to be a type. */ |
| 1124 | if (field && strcmp(field, "type") == 0) { |
| 1125 | return false; |
| 1126 | } |
| 1127 | |
| 1128 | const char *kind = ts_node_type(parent); |
| 1129 | if (kind_in_exact_set(kind, common_whole_binding_nodes) || |
| 1130 | kind_in_exact_set(kind, occurrence->whole_binding_nodes)) { |
| 1131 | return true; |
| 1132 | } |
| 1133 | |
| 1134 | bool variable_container = |
| 1135 | spec->variable_node_types && cbm_kind_in_set(parent, spec->variable_node_types); |
| 1136 | if (ctx->language == CBM_LANG_ELIXIR && strcmp(kind, "binary_operator") == 0) { |
| 1137 | variable_container = elixir_binary_operator_binds(ctx, parent); |
| 1138 | } |
| 1139 | bool declared_container = |
| 1140 | kind_in_exact_set(kind, field_binding_nodes) || |
| 1141 | (spec->function_node_types && cbm_kind_in_set(parent, spec->function_node_types)) || |
| 1142 | (spec->class_node_types && cbm_kind_in_set(parent, spec->class_node_types)) || |
| 1143 | (spec->field_node_types && cbm_kind_in_set(parent, spec->field_node_types)) || |
| 1144 | variable_container; |
| 1145 | if (declared_container) { |
| 1146 | for (const char *const *binding_field = binding_fields; *binding_field; |
| 1147 | binding_field++) { |
| 1148 | if (field_contains_node(parent, *binding_field, node)) { |
| 1149 | return true; |
| 1150 | } |
| 1151 | } |
| 1152 | } |
| 1153 | current = parent; |
| 1154 | } |
no test coverage detected