Is this an identifier-like node that represents a reference?
| 81 | |
| 82 | // Is this an identifier-like node that represents a reference? |
| 83 | static bool is_reference_node(TSNode node, CBMLanguage lang) { |
| 84 | const char *kind = ts_node_type(node); |
| 85 | |
| 86 | /* Python's attribute node and its terminal identifier describe the same |
| 87 | * source occurrence. For a direct callable-value argument, keep the leaf |
| 88 | * as the raw carrier (so unresolved cases retain a useful short-name |
| 89 | * USAGE) and stamp it with the full attribute span below. Receivers remain |
| 90 | * independent value references. */ |
| 91 | if (lang == CBM_LANG_PYTHON && strcmp(kind, "attribute") == 0 && |
| 92 | !ts_node_is_null(python_direct_callable_attribute_site(node))) { |
| 93 | return false; |
| 94 | } |
| 95 | |
| 96 | /* A Rust scoped_identifier owns the complete path occurrence. Its nested |
| 97 | * path/identifier children are grammar structure, not additional value |
| 98 | * references; keeping them would let a short-name fallback bind a decoy. */ |
| 99 | if (lang == CBM_LANG_RUST && |
| 100 | (strcmp(kind, "identifier") == 0 || strcmp(kind, "scoped_identifier") == 0)) { |
| 101 | TSNode parent = ts_node_parent(node); |
| 102 | if (!ts_node_is_null(parent) && strcmp(ts_node_type(parent), "scoped_identifier") == 0) { |
| 103 | return false; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | /* Some grammars expose the sigil/scope as a named wrapper around a generic |
| 108 | * identifier. Keep exactly one occurrence: the wrapper carries the source |
| 109 | * spelling that resolution needs (`$watched`, `a:watched`). |
| 110 | * |
| 111 | * The language gate MUST precede the parent fetch: ts_node_parent descends |
| 112 | * from the root (O(depth)), and fetching it for every identifier in every |
| 113 | * language made deep-nesting extraction quadratic across the board (the |
| 114 | * stack_overflow deep tests went 0-1s -> 39-119s and blew the suite |
| 115 | * budget on every non-M4 venue). */ |
| 116 | if ((lang == CBM_LANG_PUPPET || lang == CBM_LANG_VIMSCRIPT) && |
| 117 | strcmp(kind, "identifier") == 0) { |
| 118 | TSNode parent = ts_node_parent(node); |
| 119 | if (!ts_node_is_null(parent) && |
| 120 | ((lang == CBM_LANG_PUPPET && strcmp(ts_node_type(parent), "variable") == 0) || |
| 121 | (lang == CBM_LANG_VIMSCRIPT && strcmp(ts_node_type(parent), "argument") == 0))) { |
| 122 | return false; |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | // Common identifier types across languages |
| 127 | if (strcmp(kind, "identifier") == 0 || strcmp(kind, "simple_identifier") == 0 || |
| 128 | strcmp(kind, "type_identifier") == 0) { |
| 129 | return true; |
| 130 | } |
| 131 | |
| 132 | // Language-specific reference types |
| 133 | switch (lang) { |
| 134 | case CBM_LANG_JAVASCRIPT: |
| 135 | case CBM_LANG_TYPESCRIPT: |
| 136 | case CBM_LANG_TSX: |
| 137 | case CBM_LANG_QML: |
| 138 | case CBM_LANG_CFSCRIPT: |
| 139 | return strcmp(kind, "property_identifier") == 0 || |
| 140 | strcmp(kind, "private_property_identifier") == 0; |
no test coverage detected