Metal (.metal) and CUDA (.cu/.cuh) are C++-derived GPU languages that route
through the C++ extractor, but their qualifiers are not part of the C++ grammar:
- Metal address-space / function qualifiers: `device`, `constant`,
`threadgroup`, `thread`, `kernel`, `vertex`, `fragment`, ...
- CUDA execution-space / memory qualifiers: `__global__`, `__device__`,
`__host__`, `__shared__`, `__constant__`, `__forceinline__`, ...
tree-sitter-cpp parses a leading qualifier as the declaration's
`type_identifier` (the real type is pushed into an ERROR node), and
`_cpp_collect_type_refs` emitted it as a type reference. Each qualifier then
became a sourceless, corpus-shared god node that every shader/kernel
`references` (e.g. `kernel`/`device`/`constant` on sample.metal,
`__global__`/`__device__`/`__host__` on sample.cu, the CUDA ones colliding on
ids `global`/`device`/`host`). That is a provenance violation — a node with no
source_file — and the hubs also pollute god-node rankings in analyze.
Skip a fixed per-extension set of dialect qualifier keywords in the C++
type-ref collector, keyed by file extension so plain `.cpp`/`.cc`/`.h` files
are untouched (there these words are legal identifiers and still resolve as
real user types). Genuine user types in the shader/kernel (the `Vec3` struct)
are preserved.
Documented limitation: `constant Foo* p` buries the real `Foo` type inside the
ERROR node, so `Foo` is not recovered; this change only removes the bogus
qualifier node.